diff options
author | Thomas Haller <thaller@redhat.com> | 2019-12-15 14:28:45 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2019-12-16 10:22:09 +0100 |
commit | 9e02a676196300370487b39cbcff4e28d6c5f27c (patch) | |
tree | af6373d1ca2b7cd64994fc9c875964267ae5277a | |
parent | a1771c738dd2e1437bd9f7c73805fd8a1b1b3d1d (diff) | |
parent | 0d155d1821875ab0de1ebe95570e5684daeb7d52 (diff) | |
download | NetworkManager-9e02a676196300370487b39cbcff4e28d6c5f27c.tar.gz |
systemd: merge branch systemd into master
31 files changed, 1601 insertions, 109 deletions
diff --git a/Makefile.am b/Makefile.am index 8b75426009..abee1d13c5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1788,10 +1788,10 @@ shared_systemd_libnm_systemd_shared_la_SOURCES = \ shared/systemd/sd-adapt-shared/locale-util.h \ shared/systemd/sd-adapt-shared/memfd-util.h \ shared/systemd/sd-adapt-shared/missing_fs.h \ + shared/systemd/sd-adapt-shared/missing_keyctl.h \ shared/systemd/sd-adapt-shared/missing_magic.h \ shared/systemd/sd-adapt-shared/missing_network.h \ shared/systemd/sd-adapt-shared/missing_sched.h \ - shared/systemd/sd-adapt-shared/missing_syscall.h \ shared/systemd/sd-adapt-shared/missing_timerfd.h \ shared/systemd/sd-adapt-shared/mkdir.h \ shared/systemd/sd-adapt-shared/namespace-util.h \ @@ -1849,6 +1849,7 @@ shared_systemd_libnm_systemd_shared_la_SOURCES = \ shared/systemd/src/basic/missing_random.h \ shared/systemd/src/basic/missing_socket.h \ shared/systemd/src/basic/missing_stat.h \ + shared/systemd/src/basic/missing_syscall.h \ shared/systemd/src/basic/missing_type.h \ shared/systemd/src/basic/parse-util.c \ shared/systemd/src/basic/parse-util.h \ @@ -1861,6 +1862,7 @@ shared_systemd_libnm_systemd_shared_la_SOURCES = \ shared/systemd/src/basic/random-util.c \ shared/systemd/src/basic/random-util.h \ shared/systemd/src/basic/set.h \ + shared/systemd/src/basic/signal-util.c \ shared/systemd/src/basic/signal-util.h \ shared/systemd/src/basic/siphash24.h \ shared/systemd/src/basic/socket-util.c \ diff --git a/config.h.meson b/config.h.meson index 0a83f82568..a2874f7703 100644 --- a/config.h.meson +++ b/config.h.meson @@ -251,3 +251,7 @@ /* Define to `int' if <sys/types.h> does not define. */ #mesondefine pid_t + +#mesondefine HAVE_PIDFD_OPEN +#mesondefine HAVE_PIDFD_SEND_SIGNAL +#mesondefine HAVE_RT_SIGQUEUEINFO diff --git a/configure.ac b/configure.ac index 44bf51a11f..4889c536a5 100644 --- a/configure.ac +++ b/configure.ac @@ -91,6 +91,33 @@ AC_CHECK_DECLS([ #include <sys/mman.h> ]]) +AC_CHECK_DECLS([ + pidfd_open], + [], [], [[ +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> +#include <sys/wait.h> +]]) + +AC_CHECK_DECLS([ + pidfd_send_signal], + [], [], [[ +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> +#include <sys/wait.h> +]]) + +AC_CHECK_DECLS([ + rt_sigqueueinfo], + [], [], [[ +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> +#include <sys/wait.h> +]]) + AC_CHECK_HEADERS(sys/auxv.h) AC_CHECK_DECLS([getrandom], diff --git a/meson.build b/meson.build index faca209e1f..f02bf954ac 100644 --- a/meson.build +++ b/meson.build @@ -110,8 +110,18 @@ use_sys_random = cc.has_function('getrandom', prefix: '#include <sys/random.h>') config_h.set10('USE_SYS_RANDOM_H', use_sys_random) config_h.set10('HAVE_GETRANDOM', use_sys_random or cc.has_function('getrandom', prefix: '#include <linux/random.h>')) -# functions -# FIXME secure_getenv check is not useful? +config_h.set10('HAVE_PIDFD_OPEN', cc.has_function('pidfd_open', prefix: '''#include <stdlib.h> + #include <unistd.h> + #include <signal.h> + #include <sys/wait.h>''')) +config_h.set10('HAVE_PIDFD_SEND_SIGNAL', cc.has_function('pidfd_send_signal', prefix: '''#include <stdlib.h> + #include <unistd.h> + #include <signal.h> + #include <sys/wait.h>''')) +config_h.set10('HAVE_RT_SIGQUEUEINFO', cc.has_function('rt_sigqueueinfo', prefix: '''#include <stdlib.h> + #include <unistd.h> + #include <signal.h> + #include <sys/wait.h>''')) config_h.set('HAVE_SECURE_GETENV', cc.has_function('secure_getenv')) config_h.set('HAVE___SECURE_GETENV', cc.has_function('__secure_getenv')) config_h.set10('HAVE_DECL_REALLOCARRAY', cc.has_function('reallocarray', prefix: '#include <malloc.h>')) diff --git a/shared/meson.build b/shared/meson.build index d6ba659bbd..dd350cd0aa 100644 --- a/shared/meson.build +++ b/shared/meson.build @@ -187,10 +187,11 @@ libnm_udev_aux_dep = declare_dependency( ) sources = files( + 'systemd/nm-sd-utils-shared.c', 'systemd/src/basic/alloc-util.c', - 'systemd/src/basic/escape.c', 'systemd/src/basic/env-file.c', 'systemd/src/basic/env-util.c', + 'systemd/src/basic/escape.c', 'systemd/src/basic/ether-addr-util.c', 'systemd/src/basic/extract-word.c', 'systemd/src/basic/fd-util.c', @@ -210,6 +211,7 @@ sources = files( 'systemd/src/basic/prioq.c', 'systemd/src/basic/process-util.c', 'systemd/src/basic/random-util.c', + 'systemd/src/basic/signal-util.c', 'systemd/src/basic/socket-util.c', 'systemd/src/basic/stat-util.c', 'systemd/src/basic/string-table.c', @@ -221,7 +223,6 @@ sources = files( 'systemd/src/basic/utf8.c', 'systemd/src/basic/util.c', 'systemd/src/shared/dns-domain.c', - 'systemd/nm-sd-utils-shared.c', ) incs = include_directories( diff --git a/shared/systemd/sd-adapt-shared/missing_syscall.h b/shared/systemd/sd-adapt-shared/missing_keyctl.h index 637892c2d6..637892c2d6 100644 --- a/shared/systemd/sd-adapt-shared/missing_syscall.h +++ b/shared/systemd/sd-adapt-shared/missing_keyctl.h diff --git a/shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h b/shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h index 490cae9283..d4df97d6e5 100644 --- a/shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h +++ b/shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h @@ -122,6 +122,24 @@ static inline pid_t _nm_gettid(void) { #define HAVE_EXPLICIT_BZERO 0 #endif +#if defined(HAVE_DECL_PIDFD_OPEN) && HAVE_DECL_PIDFD_OPEN == 1 +#define HAVE_PIDFD_OPEN 1 +#else +#define HAVE_PIDFD_OPEN 0 +#endif + +#if defined(HAVE_DECL_PIDFD_SEND_SIGNAL) && HAVE_DECL_PIDFD_SEND_SIGNAL == 1 +#define HAVE_PIDFD_SEND_SIGNAL 1 +#else +#define HAVE_PIDFD_SEND_SIGNAL 0 +#endif + +#if defined(HAVE_DECL_RT_SIGQUEUEINFO) && HAVE_DECL_RT_SIGQUEUEINFO == 1 +#define HAVE_RT_SIGQUEUEINFO 1 +#else +#define HAVE_RT_SIGQUEUEINFO 0 +#endif + #endif /* (NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_SYSTEMD */ /*****************************************************************************/ diff --git a/shared/systemd/src/basic/errno-util.h b/shared/systemd/src/basic/errno-util.h index 8f1be6c00e..65a6384eeb 100644 --- a/shared/systemd/src/basic/errno-util.h +++ b/shared/systemd/src/basic/errno-util.h @@ -101,3 +101,11 @@ static inline bool ERRNO_IS_PRIVILEGE(int r) { EACCES, EPERM); } + +/* Three difference errors for "not enough disk space" */ +static inline bool ERRNO_IS_DISK_SPACE(int r) { + return IN_SET(abs(r), + ENOSPC, + EDQUOT, + EFBIG); +} diff --git a/shared/systemd/src/basic/fs-util.c b/shared/systemd/src/basic/fs-util.c index e30f40fb80..5964639026 100644 --- a/shared/systemd/src/basic/fs-util.c +++ b/shared/systemd/src/basic/fs-util.c @@ -551,6 +551,7 @@ int get_files_in_directory(const char *path, char ***list) { return n; } +#endif /* NM_IGNORED */ static int getenv_tmp_dir(const char **ret_path) { const char *n; @@ -622,6 +623,7 @@ static int tmp_dir_internal(const char *def, const char **ret) { return 0; } +#if 0 /* NM_IGNORED */ int var_tmp_dir(const char **ret) { /* Returns the location for "larger" temporary files, that is backed by physical storage if available, and thus @@ -631,6 +633,7 @@ int var_tmp_dir(const char **ret) { return tmp_dir_internal("/var/tmp", ret); } +#endif /* NM_IGNORED */ int tmp_dir(const char **ret) { @@ -640,6 +643,7 @@ int tmp_dir(const char **ret) { return tmp_dir_internal("/tmp", ret); } +#if 0 /* NM_IGNORED */ int unlink_or_warn(const char *filename) { if (unlink(filename) < 0 && errno != ENOENT) /* If the file doesn't exist and the fs simply was read-only (in which diff --git a/shared/systemd/src/basic/macro.h b/shared/systemd/src/basic/macro.h index fc733366b3..6cd9c516fb 100644 --- a/shared/systemd/src/basic/macro.h +++ b/shared/systemd/src/basic/macro.h @@ -172,6 +172,11 @@ static inline size_t ALIGN_TO(size_t l, size_t ali) { /* align to next higher power-of-2 (except for: 0 => 0, overflow => 0) */ static inline unsigned long ALIGN_POWER2(unsigned long u) { + + /* Avoid subtraction overflow */ + if (u == 0) + return 0; + /* clz(0) is undefined */ if (u == 1) return 1; @@ -183,6 +188,29 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { return 1UL << (sizeof(u) * 8 - __builtin_clzl(u - 1UL)); } +static inline size_t GREEDY_ALLOC_ROUND_UP(size_t l) { + size_t m; + + /* Round up allocation sizes a bit to some reasonable, likely larger value. This is supposed to be + * used for cases which are likely called in an allocation loop of some form, i.e. that repetitively + * grow stuff, for example strv_extend() and suchlike. + * + * Note the difference to GREEDY_REALLOC() here, as this helper operates on a single size value only, + * and rounds up to next multiple of 2, needing no further counter. + * + * Note the benefits of direct ALIGN_POWER2() usage: type-safety for size_t, sane handling for very + * small (i.e. <= 2) and safe handling for very large (i.e. > SSIZE_MAX) values. */ + + if (l <= 2) + return 2; /* Never allocate less than 2 of something. */ + + m = ALIGN_POWER2(l); + if (m == 0) /* overflow? */ + return l; + + return m; +} + #ifndef __COVERITY__ # define VOID_0 ((void)0) #else diff --git a/shared/systemd/src/basic/memory-util.h b/shared/systemd/src/basic/memory-util.h index 46a6907a0c..4f92a6434a 100644 --- a/shared/systemd/src/basic/memory-util.h +++ b/shared/systemd/src/basic/memory-util.h @@ -80,14 +80,21 @@ static inline void* explicit_bzero_safe(void *p, size_t l) { void *explicit_bzero_safe(void *p, size_t l); #endif -static inline void erase_and_freep(void *p) { - void *ptr = *(void**) p; +static inline void* erase_and_free(void *p) { + size_t l; + + if (!p) + return NULL; + + l = malloc_usable_size(p); + explicit_bzero_safe(p, l); + free(p); - if (ptr) { - size_t l = malloc_usable_size(ptr); - explicit_bzero_safe(ptr, l); - free(ptr); - } + return NULL; +} + +static inline void erase_and_freep(void *p) { + erase_and_free(*(void**) p); } /* Use with _cleanup_ to erase a single 'char' when leaving scope */ diff --git a/shared/systemd/src/basic/missing_syscall.h b/shared/systemd/src/basic/missing_syscall.h new file mode 100644 index 0000000000..4c42e66515 --- /dev/null +++ b/shared/systemd/src/basic/missing_syscall.h @@ -0,0 +1,574 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +/* Missing glibc definitions to access certain kernel APIs */ + +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <sys/syscall.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +#ifdef ARCH_MIPS +#include <asm/sgidefs.h> +#endif + +#include "missing_keyctl.h" +#include "missing_stat.h" + +#if 0 /* NM_IGNORED */ + +/* linux/kcmp.h */ +#ifndef KCMP_FILE /* 3f4994cfc15f38a3159c6e3a4b3ab2e1481a6b02 (3.19) */ +#define KCMP_FILE 0 +#endif + +#if !HAVE_PIVOT_ROOT +static inline int missing_pivot_root(const char *new_root, const char *put_old) { + return syscall(__NR_pivot_root, new_root, put_old); +} + +# define pivot_root missing_pivot_root +#endif + +/* ======================================================================= */ + +#if !HAVE_MEMFD_CREATE +/* may be (invalid) negative number due to libseccomp, see PR 13319 */ +# if ! (defined __NR_memfd_create && __NR_memfd_create >= 0) +# if defined __NR_memfd_create +# undef __NR_memfd_create +# endif +# if defined __x86_64__ +# define __NR_memfd_create 319 +# elif defined __arm__ +# define __NR_memfd_create 385 +# elif defined __aarch64__ +# define __NR_memfd_create 279 +# elif defined __s390__ +# define __NR_memfd_create 350 +# elif defined _MIPS_SIM +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define __NR_memfd_create 4354 +# endif +# if _MIPS_SIM == _MIPS_SIM_NABI32 +# define __NR_memfd_create 6318 +# endif +# if _MIPS_SIM == _MIPS_SIM_ABI64 +# define __NR_memfd_create 5314 +# endif +# elif defined __i386__ +# define __NR_memfd_create 356 +# elif defined __arc__ +# define __NR_memfd_create 279 +# else +# warning "__NR_memfd_create unknown for your architecture" +# endif +# endif + +static inline int missing_memfd_create(const char *name, unsigned int flags) { +# ifdef __NR_memfd_create + return syscall(__NR_memfd_create, name, flags); +# else + errno = ENOSYS; + return -1; +# endif +} + +# define memfd_create missing_memfd_create +#endif + +/* ======================================================================= */ + +#if !HAVE_GETRANDOM +/* may be (invalid) negative number due to libseccomp, see PR 13319 */ +# if ! (defined __NR_getrandom && __NR_getrandom >= 0) +# if defined __NR_getrandom +# undef __NR_getrandom +# endif +# if defined __x86_64__ +# define __NR_getrandom 318 +# elif defined(__i386__) +# define __NR_getrandom 355 +# elif defined(__arm__) +# define __NR_getrandom 384 +# elif defined(__aarch64__) +# define __NR_getrandom 278 +# elif defined(__ia64__) +# define __NR_getrandom 1339 +# elif defined(__m68k__) +# define __NR_getrandom 352 +# elif defined(__s390x__) +# define __NR_getrandom 349 +# elif defined(__powerpc__) +# define __NR_getrandom 359 +# elif defined _MIPS_SIM +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define __NR_getrandom 4353 +# endif +# if _MIPS_SIM == _MIPS_SIM_NABI32 +# define __NR_getrandom 6317 +# endif +# if _MIPS_SIM == _MIPS_SIM_ABI64 +# define __NR_getrandom 5313 +# endif +# elif defined(__arc__) +# define __NR_getrandom 278 +# else +# warning "__NR_getrandom unknown for your architecture" +# endif +# endif + +static inline int missing_getrandom(void *buffer, size_t count, unsigned flags) { +# ifdef __NR_getrandom + return syscall(__NR_getrandom, buffer, count, flags); +# else + errno = ENOSYS; + return -1; +# endif +} + +# define getrandom missing_getrandom +#endif + +/* ======================================================================= */ + +#if !HAVE_GETTID +static inline pid_t missing_gettid(void) { + return (pid_t) syscall(__NR_gettid); +} + +# define gettid missing_gettid +#endif + +/* ======================================================================= */ + +#if !HAVE_NAME_TO_HANDLE_AT +/* may be (invalid) negative number due to libseccomp, see PR 13319 */ +# if ! (defined __NR_name_to_handle_at && __NR_name_to_handle_at >= 0) +# if defined __NR_name_to_handle_at +# undef __NR_name_to_handle_at +# endif +# if defined(__x86_64__) +# define __NR_name_to_handle_at 303 +# elif defined(__i386__) +# define __NR_name_to_handle_at 341 +# elif defined(__arm__) +# define __NR_name_to_handle_at 370 +# elif defined(__powerpc__) +# define __NR_name_to_handle_at 345 +# elif defined(__arc__) +# define __NR_name_to_handle_at 264 +# else +# error "__NR_name_to_handle_at is not defined" +# endif +# endif + +struct file_handle { + unsigned int handle_bytes; + int handle_type; + unsigned char f_handle[0]; +}; + +static inline int missing_name_to_handle_at(int fd, const char *name, struct file_handle *handle, int *mnt_id, int flags) { +# ifdef __NR_name_to_handle_at + return syscall(__NR_name_to_handle_at, fd, name, handle, mnt_id, flags); +# else + errno = ENOSYS; + return -1; +# endif +} + +# define name_to_handle_at missing_name_to_handle_at +#endif + +/* ======================================================================= */ + +#if !HAVE_SETNS +/* may be (invalid) negative number due to libseccomp, see PR 13319 */ +# if ! (defined __NR_setns && __NR_setns >= 0) +# if defined __NR_setns +# undef __NR_setns +# endif +# if defined(__x86_64__) +# define __NR_setns 308 +# elif defined(__i386__) +# define __NR_setns 346 +# elif defined(__arc__) +# define __NR_setns 268 +# else +# error "__NR_setns is not defined" +# endif +# endif + +static inline int missing_setns(int fd, int nstype) { +# ifdef __NR_setns + return syscall(__NR_setns, fd, nstype); +# else + errno = ENOSYS; + return -1; +# endif +} + +# define setns missing_setns +#endif + +/* ======================================================================= */ + +static inline pid_t raw_getpid(void) { +#if defined(__alpha__) + return (pid_t) syscall(__NR_getxpid); +#else + return (pid_t) syscall(__NR_getpid); +#endif +} + +/* ======================================================================= */ + +#if !HAVE_RENAMEAT2 +/* may be (invalid) negative number due to libseccomp, see PR 13319 */ +# if ! (defined __NR_renameat2 && __NR_renameat2 >= 0) +# if defined __NR_renameat2 +# undef __NR_renameat2 +# endif +# if defined __x86_64__ +# define __NR_renameat2 316 +# elif defined __arm__ +# define __NR_renameat2 382 +# elif defined __aarch64__ +# define __NR_renameat2 276 +# elif defined _MIPS_SIM +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define __NR_renameat2 4351 +# endif +# if _MIPS_SIM == _MIPS_SIM_NABI32 +# define __NR_renameat2 6315 +# endif +# if _MIPS_SIM == _MIPS_SIM_ABI64 +# define __NR_renameat2 5311 +# endif +# elif defined __i386__ +# define __NR_renameat2 353 +# elif defined __powerpc64__ +# define __NR_renameat2 357 +# elif defined __s390__ || defined __s390x__ +# define __NR_renameat2 347 +# elif defined __arc__ +# define __NR_renameat2 276 +# else +# warning "__NR_renameat2 unknown for your architecture" +# endif +# endif + +static inline int missing_renameat2(int oldfd, const char *oldname, int newfd, const char *newname, unsigned flags) { +# ifdef __NR_renameat2 + return syscall(__NR_renameat2, oldfd, oldname, newfd, newname, flags); +# else + errno = ENOSYS; + return -1; +# endif +} + +# define renameat2 missing_renameat2 +#endif + +/* ======================================================================= */ + +#if !HAVE_KCMP +static inline int missing_kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) { +# if defined __NR_kcmp && __NR_kcmp >= 0 + return syscall(__NR_kcmp, pid1, pid2, type, idx1, idx2); +# else + errno = ENOSYS; + return -1; +# endif +} + +# define kcmp missing_kcmp +#endif + +/* ======================================================================= */ + +#if !HAVE_KEYCTL +static inline long missing_keyctl(int cmd, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) { +# if defined __NR_keyctl && __NR_keyctl >= 0 + return syscall(__NR_keyctl, cmd, arg2, arg3, arg4, arg5); +# else + errno = ENOSYS; + return -1; +# endif + +# define keyctl missing_keyctl +} + +static inline key_serial_t missing_add_key(const char *type, const char *description, const void *payload, size_t plen, key_serial_t ringid) { +# if defined __NR_add_key && __NR_add_key >= 0 + return syscall(__NR_add_key, type, description, payload, plen, ringid); +# else + errno = ENOSYS; + return -1; +# endif + +# define add_key missing_add_key +} + +static inline key_serial_t missing_request_key(const char *type, const char *description, const char * callout_info, key_serial_t destringid) { +# if defined __NR_request_key && __NR_request_key >= 0 + return syscall(__NR_request_key, type, description, callout_info, destringid); +# else + errno = ENOSYS; + return -1; +# endif + +# define request_key missing_request_key +} +#endif + +/* ======================================================================= */ + +#if !HAVE_COPY_FILE_RANGE +/* may be (invalid) negative number due to libseccomp, see PR 13319 */ +# if ! (defined __NR_copy_file_range && __NR_copy_file_range >= 0) +# if defined __NR_copy_file_range +# undef __NR_copy_file_range +# endif +# if defined(__x86_64__) +# define __NR_copy_file_range 326 +# elif defined(__i386__) +# define __NR_copy_file_range 377 +# elif defined __s390__ +# define __NR_copy_file_range 375 +# elif defined __arm__ +# define __NR_copy_file_range 391 +# elif defined __aarch64__ +# define __NR_copy_file_range 285 +# elif defined __powerpc__ +# define __NR_copy_file_range 379 +# elif defined __arc__ +# define __NR_copy_file_range 285 +# else +# warning "__NR_copy_file_range not defined for your architecture" +# endif +# endif + +static inline ssize_t missing_copy_file_range(int fd_in, loff_t *off_in, + int fd_out, loff_t *off_out, + size_t len, + unsigned int flags) { +# ifdef __NR_copy_file_range + return syscall(__NR_copy_file_range, fd_in, off_in, fd_out, off_out, len, flags); +# else + errno = ENOSYS; + return -1; +# endif +} + +# define copy_file_range missing_copy_file_range +#endif + +/* ======================================================================= */ + +#if !HAVE_BPF +/* may be (invalid) negative number due to libseccomp, see PR 13319 */ +# if ! (defined __NR_bpf && __NR_bpf >= 0) +# if defined __NR_bpf +# undef __NR_bpf +# endif +# if defined __i386__ +# define __NR_bpf 357 +# elif defined __x86_64__ +# define __NR_bpf 321 +# elif defined __aarch64__ +# define __NR_bpf 280 +# elif defined __arm__ +# define __NR_bpf 386 +# elif defined __sparc__ +# define __NR_bpf 349 +# elif defined __s390__ +# define __NR_bpf 351 +# elif defined __tilegx__ +# define __NR_bpf 280 +# else +# warning "__NR_bpf not defined for your architecture" +# endif +# endif + +union bpf_attr; + +static inline int missing_bpf(int cmd, union bpf_attr *attr, size_t size) { +#ifdef __NR_bpf + return (int) syscall(__NR_bpf, cmd, attr, size); +#else + errno = ENOSYS; + return -1; +#endif +} + +# define bpf missing_bpf +#endif + +/* ======================================================================= */ + +#ifndef __IGNORE_pkey_mprotect +/* may be (invalid) negative number due to libseccomp, see PR 13319 */ +# if ! (defined __NR_pkey_mprotect && __NR_pkey_mprotect >= 0) +# if defined __NR_pkey_mprotect +# undef __NR_pkey_mprotect +# endif +# if defined __i386__ +# define __NR_pkey_mprotect 380 +# elif defined __x86_64__ +# define __NR_pkey_mprotect 329 +# elif defined __arm__ +# define __NR_pkey_mprotect 394 +# elif defined __aarch64__ +# define __NR_pkey_mprotect 394 +# elif defined __powerpc__ +# define __NR_pkey_mprotect 386 +# elif defined __s390__ +# define __NR_pkey_mprotect 384 +# elif defined _MIPS_SIM +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define __NR_pkey_mprotect 4363 +# endif +# if _MIPS_SIM == _MIPS_SIM_NABI32 +# define __NR_pkey_mprotect 6327 +# endif +# if _MIPS_SIM == _MIPS_SIM_ABI64 +# define __NR_pkey_mprotect 5323 +# endif +# else +# warning "__NR_pkey_mprotect not defined for your architecture" +# endif +# endif +#endif + +/* ======================================================================= */ + +#if !HAVE_STATX +/* may be (invalid) negative number due to libseccomp, see PR 13319 */ +# if ! (defined __NR_statx && __NR_statx >= 0) +# if defined __NR_statx +# undef __NR_statx +# endif +# if defined __aarch64__ || defined __arm__ +# define __NR_statx 397 +# elif defined __alpha__ +# define __NR_statx 522 +# elif defined __i386__ || defined __powerpc64__ +# define __NR_statx 383 +# elif defined __sparc__ +# define __NR_statx 360 +# elif defined __x86_64__ +# define __NR_statx 332 +# else +# warning "__NR_statx not defined for your architecture" +# endif +# endif + +struct statx; +#endif + +/* This typedef is supposed to be always defined. */ +typedef struct statx struct_statx; + +#if !HAVE_STATX +static inline ssize_t missing_statx(int dfd, const char *filename, unsigned flags, unsigned int mask, struct statx *buffer) { +# ifdef __NR_statx + return syscall(__NR_statx, dfd, filename, flags, mask, buffer); +# else + errno = ENOSYS; + return -1; +# endif +} + +# define statx missing_statx +#endif + +#if !HAVE_SET_MEMPOLICY + +enum { + MPOL_DEFAULT, + MPOL_PREFERRED, + MPOL_BIND, + MPOL_INTERLEAVE, + MPOL_LOCAL, +}; + +static inline long missing_set_mempolicy(int mode, const unsigned long *nodemask, + unsigned long maxnode) { + long i; +# if defined __NR_set_mempolicy && __NR_set_mempolicy >= 0 + i = syscall(__NR_set_mempolicy, mode, nodemask, maxnode); +# else + errno = ENOSYS; + i = -1; +# endif + return i; +} + +# define set_mempolicy missing_set_mempolicy +#endif + +#if !HAVE_GET_MEMPOLICY +static inline long missing_get_mempolicy(int *mode, unsigned long *nodemask, + unsigned long maxnode, void *addr, + unsigned long flags) { + long i; +# ifdef __NR_get_mempolicy + i = syscall(__NR_get_mempolicy, mode, nodemask, maxnode, addr, flags); +# else + errno = ENOSYS; + i = -1; +# endif + return i; +} + +#define get_mempolicy missing_get_mempolicy +#endif + +#endif /* NM_IGNORED */ + +#if !HAVE_PIDFD_OPEN +/* may be (invalid) negative number due to libseccomp, see PR 13319 */ +# if ! (defined __NR_pidfd_open && __NR_pidfd_open >= 0) +# if defined __NR_pidfd_open +# undef __NR_pidfd_open +# endif +# define __NR_pidfd_open 434 +#endif +static inline int pidfd_open(pid_t pid, unsigned flags) { +#ifdef __NR_pidfd_open + return syscall(__NR_pidfd_open, pid, flags); +#else + errno = ENOSYS; + return -1; +#endif +} +#endif + +#if !HAVE_PIDFD_SEND_SIGNAL +/* may be (invalid) negative number due to libseccomp, see PR 13319 */ +# if ! (defined __NR_pidfd_send_signal && __NR_pidfd_send_signal >= 0) +# if defined __NR_pidfd_send_signal +# undef __NR_pidfd_send_signal +# endif +# define __NR_pidfd_send_signal 424 +#endif +static inline int pidfd_send_signal(int fd, int sig, siginfo_t *info, unsigned flags) { +#ifdef __NR_pidfd_open + return syscall(__NR_pidfd_send_signal, fd, sig, info, flags); +#else + errno = ENOSYS; + return -1; +#endif +} +#endif + +#if !HAVE_RT_SIGQUEUEINFO +static inline int rt_sigqueueinfo(pid_t tgid, int sig, siginfo_t *info) { + return syscall(__NR_rt_sigqueueinfo, tgid, sig, info); +} +#endif diff --git a/shared/systemd/src/basic/parse-util.c b/shared/systemd/src/basic/parse-util.c index 96cc43a2ae..1199ca8003 100644 --- a/shared/systemd/src/basic/parse-util.c +++ b/shared/systemd/src/basic/parse-util.c @@ -369,7 +369,6 @@ int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) { unsigned long l; assert(s); - assert(ret_u); assert(base <= 16); /* strtoul() is happy to parse negative values, and silently @@ -393,7 +392,9 @@ int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) { if ((unsigned long) (unsigned) l != l) return -ERANGE; - *ret_u = (unsigned) l; + if (ret_u) + *ret_u = (unsigned) l; + return 0; } @@ -402,7 +403,6 @@ int safe_atoi(const char *s, int *ret_i) { long l; assert(s); - assert(ret_i); errno = 0; l = strtol(s, &x, 0); @@ -413,7 +413,9 @@ int safe_atoi(const char *s, int *ret_i) { if ((long) (int) l != l) return -ERANGE; - *ret_i = (int) l; + if (ret_i) + *ret_i = (int) l; + return 0; } @@ -422,7 +424,6 @@ int safe_atollu(const char *s, long long unsigned *ret_llu) { unsigned long long l; assert(s); - assert(ret_llu); s += strspn(s, WHITESPACE); @@ -435,7 +436,9 @@ int safe_atollu(const char *s, long long unsigned *ret_llu) { if (*s == '-') return -ERANGE; - *ret_llu = l; + if (ret_llu) + *ret_llu = l; + return 0; } @@ -444,7 +447,6 @@ int safe_atolli(const char *s, long long int *ret_lli) { long long l; assert(s); - assert(ret_lli); errno = 0; l = strtoll(s, &x, 0); @@ -453,7 +455,9 @@ int safe_atolli(const char *s, long long int *ret_lli) { if (!x || x == s || *x != 0) return -EINVAL; - *ret_lli = l; + if (ret_lli) + *ret_lli = l; + return 0; } @@ -462,7 +466,6 @@ int safe_atou8(const char *s, uint8_t *ret) { unsigned long l; assert(s); - assert(ret); s += strspn(s, WHITESPACE); @@ -477,7 +480,8 @@ int safe_atou8(const char *s, uint8_t *ret) { if ((unsigned long) (uint8_t) l != l) return -ERANGE; - *ret = (uint8_t) l; + if (ret) + *ret = (uint8_t) l; return 0; } @@ -511,7 +515,6 @@ int safe_atoi16(const char *s, int16_t *ret) { long l; assert(s); - assert(ret); errno = 0; l = strtol(s, &x, 0); @@ -522,7 +525,9 @@ int safe_atoi16(const char *s, int16_t *ret) { if ((long) (int16_t) l != l) return -ERANGE; - *ret = (int16_t) l; + if (ret) + *ret = (int16_t) l; + return 0; } @@ -533,7 +538,6 @@ int safe_atod(const char *s, double *ret_d) { double d = 0; assert(s); - assert(ret_d); loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0); if (loc == (locale_t) 0) @@ -546,7 +550,9 @@ int safe_atod(const char *s, double *ret_d) { if (!x || x == s || *x != 0) return -EINVAL; - *ret_d = (double) d; + if (ret_d) + *ret_d = (double) d; + return 0; } diff --git a/shared/systemd/src/basic/path-util.c b/shared/systemd/src/basic/path-util.c index 5bcc35e5dd..4250ea1872 100644 --- a/shared/systemd/src/basic/path-util.c +++ b/shared/systemd/src/basic/path-util.c @@ -540,6 +540,7 @@ bool path_equal(const char *a, const char *b) { bool path_equal_or_files_same(const char *a, const char *b, int flags) { return path_equal(a, b) || files_same(a, b, flags) > 0; } +#endif /* NM_IGNORED */ char* path_join_internal(const char *first, ...) { char *joined, *q; @@ -599,6 +600,7 @@ char* path_join_internal(const char *first, ...) { return joined; } +#if 0 /* NM_IGNORED */ int find_binary(const char *name, char **ret) { int last_error, r; const char *p; diff --git a/shared/systemd/src/basic/process-util.c b/shared/systemd/src/basic/process-util.c index 1456167063..deba989a46 100644 --- a/shared/systemd/src/basic/process-util.c +++ b/shared/systemd/src/basic/process-util.c @@ -44,6 +44,7 @@ #include "rlimit-util.h" #include "signal-util.h" #include "stat-util.h" +#include "stdio-util.h" #include "string-table.h" #include "string-util.h" #include "terminal-util.h" @@ -1347,6 +1348,12 @@ int safe_fork_full( log_full_errno(prio, r, "Failed to connect stdin/stdout to /dev/null: %m"); _exit(EXIT_FAILURE); } + + } else if (flags & FORK_STDOUT_TO_STDERR) { + if (dup2(STDERR_FILENO, STDOUT_FILENO) < 0) { + log_full_errno(prio, errno, "Failed to connect stdout to stderr: %m"); + _exit(EXIT_FAILURE); + } } if (flags & FORK_RLIMIT_NOFILE_SAFE) { @@ -1498,6 +1505,38 @@ int set_oom_score_adjust(int value) { WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_DISABLE_BUFFER); } +int pidfd_get_pid(int fd, pid_t *ret) { + char path[STRLEN("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)]; + _cleanup_free_ char *fdinfo = NULL; + char *p; + int r; + + if (fd < 0) + return -EBADF; + + xsprintf(path, "/proc/self/fdinfo/%i", fd); + + r = read_full_file(path, &fdinfo, NULL); + if (r == -ENOENT) /* if fdinfo doesn't exist we assume the process does not exist */ + return -ESRCH; + if (r < 0) + return r; + + p = startswith(fdinfo, "Pid:"); + if (!p) { + p = strstr(fdinfo, "\nPid:"); + if (!p) + return -ENOTTY; /* not a pidfd? */ + + p += 5; + } + + p += strspn(p, WHITESPACE); + p[strcspn(p, WHITESPACE)] = 0; + + return parse_pid(p, ret); +} + 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 66853c6e8d..cb96b43f21 100644 --- a/shared/systemd/src/basic/process-util.h +++ b/shared/systemd/src/basic/process-util.h @@ -149,16 +149,17 @@ void reset_cached_pid(void); int must_be_root(void); typedef enum ForkFlags { - FORK_RESET_SIGNALS = 1 << 0, /* Reset all signal handlers and signal mask */ - FORK_CLOSE_ALL_FDS = 1 << 1, /* Close all open file descriptors in the child, except for 0,1,2 */ - FORK_DEATHSIG = 1 << 2, /* Set PR_DEATHSIG in the child */ - FORK_NULL_STDIO = 1 << 3, /* Connect 0,1,2 to /dev/null */ - FORK_REOPEN_LOG = 1 << 4, /* Reopen log connection */ - FORK_LOG = 1 << 5, /* Log above LOG_DEBUG log level about failures */ - FORK_WAIT = 1 << 6, /* Wait until child exited */ - FORK_NEW_MOUNTNS = 1 << 7, /* Run child in its own mount namespace */ - FORK_MOUNTNS_SLAVE = 1 << 8, /* Make child's mount namespace MS_SLAVE */ - FORK_RLIMIT_NOFILE_SAFE = 1 << 9, /* Set RLIMIT_NOFILE soft limit to 1K for select() compat */ + FORK_RESET_SIGNALS = 1 << 0, /* Reset all signal handlers and signal mask */ + FORK_CLOSE_ALL_FDS = 1 << 1, /* Close all open file descriptors in the child, except for 0,1,2 */ + FORK_DEATHSIG = 1 << 2, /* Set PR_DEATHSIG in the child */ + FORK_NULL_STDIO = 1 << 3, /* Connect 0,1,2 to /dev/null */ + FORK_REOPEN_LOG = 1 << 4, /* Reopen log connection */ + FORK_LOG = 1 << 5, /* Log above LOG_DEBUG log level about failures */ + FORK_WAIT = 1 << 6, /* Wait until child exited */ + FORK_NEW_MOUNTNS = 1 << 7, /* Run child in its own mount namespace */ + FORK_MOUNTNS_SLAVE = 1 << 8, /* Make child's mount namespace MS_SLAVE */ + FORK_RLIMIT_NOFILE_SAFE = 1 << 9, /* Set RLIMIT_NOFILE soft limit to 1K for select() compat */ + FORK_STDOUT_TO_STDERR = 1 << 10, /* Make stdout a copy of stderr */ } ForkFlags; int safe_fork_full(const char *name, const int except_fds[], size_t n_except_fds, ForkFlags flags, pid_t *ret_pid); @@ -199,3 +200,5 @@ assert_cc(TASKS_MAX <= (unsigned long) PID_T_MAX); (pid) = 0; \ _pid_; \ }) + +int pidfd_get_pid(int fd, pid_t *ret); diff --git a/shared/systemd/src/basic/signal-util.c b/shared/systemd/src/basic/signal-util.c new file mode 100644 index 0000000000..a4b8163c0f --- /dev/null +++ b/shared/systemd/src/basic/signal-util.c @@ -0,0 +1,308 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "nm-sd-adapt-shared.h" + +#include <errno.h> +#include <stdarg.h> + +#include "macro.h" +#include "parse-util.h" +#include "signal-util.h" +#include "stdio-util.h" +#include "string-table.h" +#include "string-util.h" + +#if 0 /* NM_IGNORED */ +int reset_all_signal_handlers(void) { + static const struct sigaction sa = { + .sa_handler = SIG_DFL, + .sa_flags = SA_RESTART, + }; + int sig, r = 0; + + for (sig = 1; sig < _NSIG; sig++) { + + /* These two cannot be caught... */ + if (IN_SET(sig, SIGKILL, SIGSTOP)) + continue; + + /* On Linux the first two RT signals are reserved by + * glibc, and sigaction() will return EINVAL for them. */ + if (sigaction(sig, &sa, NULL) < 0) + if (errno != EINVAL && r >= 0) + r = -errno; + } + + return r; +} + +int reset_signal_mask(void) { + sigset_t ss; + + if (sigemptyset(&ss) < 0) + return -errno; + + if (sigprocmask(SIG_SETMASK, &ss, NULL) < 0) + return -errno; + + return 0; +} + +static int sigaction_many_ap(const struct sigaction *sa, int sig, va_list ap) { + int r = 0; + + /* negative signal ends the list. 0 signal is skipped. */ + + if (sig < 0) + return 0; + + if (sig > 0) { + if (sigaction(sig, sa, NULL) < 0) + r = -errno; + } + + while ((sig = va_arg(ap, int)) >= 0) { + + if (sig == 0) + continue; + + if (sigaction(sig, sa, NULL) < 0) { + if (r >= 0) + r = -errno; + } + } + + return r; +} + +int sigaction_many(const struct sigaction *sa, ...) { + va_list ap; + int r; + + va_start(ap, sa); + r = sigaction_many_ap(sa, 0, ap); + va_end(ap); + + return r; +} + +int ignore_signals(int sig, ...) { + + static const struct sigaction sa = { + .sa_handler = SIG_IGN, + .sa_flags = SA_RESTART, + }; + + va_list ap; + int r; + + va_start(ap, sig); + r = sigaction_many_ap(&sa, sig, ap); + va_end(ap); + + return r; +} + +int default_signals(int sig, ...) { + + static const struct sigaction sa = { + .sa_handler = SIG_DFL, + .sa_flags = SA_RESTART, + }; + + va_list ap; + int r; + + va_start(ap, sig); + r = sigaction_many_ap(&sa, sig, ap); + va_end(ap); + + return r; +} + +static int sigset_add_many_ap(sigset_t *ss, va_list ap) { + int sig, r = 0; + + assert(ss); + + while ((sig = va_arg(ap, int)) >= 0) { + + if (sig == 0) + continue; + + if (sigaddset(ss, sig) < 0) { + if (r >= 0) + r = -errno; + } + } + + return r; +} + +int sigset_add_many(sigset_t *ss, ...) { + va_list ap; + int r; + + va_start(ap, ss); + r = sigset_add_many_ap(ss, ap); + va_end(ap); + + return r; +} + +int sigprocmask_many(int how, sigset_t *old, ...) { + va_list ap; + sigset_t ss; + int r; + + if (sigemptyset(&ss) < 0) + return -errno; + + va_start(ap, old); + r = sigset_add_many_ap(&ss, ap); + va_end(ap); + + if (r < 0) + return r; + + if (sigprocmask(how, &ss, old) < 0) + return -errno; + + return 0; +} + +static const char *const __signal_table[] = { + [SIGHUP] = "HUP", + [SIGINT] = "INT", + [SIGQUIT] = "QUIT", + [SIGILL] = "ILL", + [SIGTRAP] = "TRAP", + [SIGABRT] = "ABRT", + [SIGBUS] = "BUS", + [SIGFPE] = "FPE", + [SIGKILL] = "KILL", + [SIGUSR1] = "USR1", + [SIGSEGV] = "SEGV", + [SIGUSR2] = "USR2", + [SIGPIPE] = "PIPE", + [SIGALRM] = "ALRM", + [SIGTERM] = "TERM", +#ifdef SIGSTKFLT + [SIGSTKFLT] = "STKFLT", /* Linux on SPARC doesn't know SIGSTKFLT */ +#endif + [SIGCHLD] = "CHLD", + [SIGCONT] = "CONT", + [SIGSTOP] = "STOP", + [SIGTSTP] = "TSTP", + [SIGTTIN] = "TTIN", + [SIGTTOU] = "TTOU", + [SIGURG] = "URG", + [SIGXCPU] = "XCPU", + [SIGXFSZ] = "XFSZ", + [SIGVTALRM] = "VTALRM", + [SIGPROF] = "PROF", + [SIGWINCH] = "WINCH", + [SIGIO] = "IO", + [SIGPWR] = "PWR", + [SIGSYS] = "SYS" +}; + +DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int); + +const char *signal_to_string(int signo) { + static thread_local char buf[STRLEN("RTMIN+") + DECIMAL_STR_MAX(int) + 1]; + const char *name; + + name = __signal_to_string(signo); + if (name) + return name; + + if (signo >= SIGRTMIN && signo <= SIGRTMAX) + xsprintf(buf, "RTMIN+%d", signo - SIGRTMIN); + else + xsprintf(buf, "%d", signo); + + return buf; +} + +int signal_from_string(const char *s) { + const char *p; + int signo, r; + + /* Check that the input is a signal number. */ + if (safe_atoi(s, &signo) >= 0) { + if (SIGNAL_VALID(signo)) + return signo; + else + return -ERANGE; + } + + /* Drop "SIG" prefix. */ + if (startswith(s, "SIG")) + s += 3; + + /* Check that the input is a signal name. */ + signo = __signal_from_string(s); + if (signo > 0) + return signo; + + /* Check that the input is RTMIN or + * RTMIN+n (0 <= n <= SIGRTMAX-SIGRTMIN). */ + p = startswith(s, "RTMIN"); + if (p) { + if (*p == '\0') + return SIGRTMIN; + if (*p != '+') + return -EINVAL; + + r = safe_atoi(p, &signo); + if (r < 0) + return r; + + if (signo < 0 || signo > SIGRTMAX - SIGRTMIN) + return -ERANGE; + + return signo + SIGRTMIN; + } + + /* Check that the input is RTMAX or + * RTMAX-n (0 <= n <= SIGRTMAX-SIGRTMIN). */ + p = startswith(s, "RTMAX"); + if (p) { + if (*p == '\0') + return SIGRTMAX; + if (*p != '-') + return -EINVAL; + + r = safe_atoi(p, &signo); + if (r < 0) + return r; + + if (signo > 0 || signo < SIGRTMIN - SIGRTMAX) + return -ERANGE; + + return signo + SIGRTMAX; + } + + return -EINVAL; +} + +void nop_signal_handler(int sig) { + /* nothing here */ +} +#endif /* NM_IGNORED */ + +int signal_is_blocked(int sig) { + sigset_t ss; + int r; + + r = pthread_sigmask(SIG_SETMASK, NULL, &ss); + if (r != 0) + return -r; + + r = sigismember(&ss, sig); + if (r < 0) + return -errno; + + return r; +} diff --git a/shared/systemd/src/basic/signal-util.h b/shared/systemd/src/basic/signal-util.h index 92f2804cd2..3909ee341d 100644 --- a/shared/systemd/src/basic/signal-util.h +++ b/shared/systemd/src/basic/signal-util.h @@ -41,3 +41,5 @@ static inline const char* signal_to_string_with_check(int n) { return signal_to_string(n); } + +int signal_is_blocked(int sig); diff --git a/shared/systemd/src/basic/stat-util.c b/shared/systemd/src/basic/stat-util.c index 071050f2e4..848812cd0f 100644 --- a/shared/systemd/src/basic/stat-util.c +++ b/shared/systemd/src/basic/stat-util.c @@ -31,6 +31,7 @@ int is_symlink(const char *path) { return !!S_ISLNK(info.st_mode); } +#endif /* NM_IGNORED */ int is_dir(const char* path, bool follow) { struct stat st; @@ -48,6 +49,7 @@ int is_dir(const char* path, bool follow) { return !!S_ISDIR(st.st_mode); } +#if 0 /* NM_IGNORED */ int is_dir_fd(int fd) { struct stat st; diff --git a/shared/systemd/src/basic/string-util.c b/shared/systemd/src/basic/string-util.c index 3d2feb181b..38cccdaf05 100644 --- a/shared/systemd/src/basic/string-util.c +++ b/shared/systemd/src/basic/string-util.c @@ -1072,3 +1072,15 @@ bool string_is_safe(const char *p) { return true; } + +#if 0 /* NM_IGNORED */ +char* string_erase(char *x) { + if (!x) + return NULL; + + /* A delicious drop of snake-oil! To be called on memory where we stored passphrases or so, after we + * used them. */ + explicit_bzero_safe(x, strlen(x)); + return x; +} +#endif /* NM_IGNORED */ diff --git a/shared/systemd/src/basic/string-util.h b/shared/systemd/src/basic/string-util.h index 04cc82b386..f10af9ad2f 100644 --- a/shared/systemd/src/basic/string-util.h +++ b/shared/systemd/src/basic/string-util.h @@ -278,3 +278,5 @@ static inline char* str_realloc(char **p) { return (*p = t); } + +char* string_erase(char *x); diff --git a/shared/systemd/src/basic/strv.c b/shared/systemd/src/basic/strv.c index aa46713264..b773254bab 100644 --- a/shared/systemd/src/basic/strv.c +++ b/shared/systemd/src/basic/strv.c @@ -195,7 +195,10 @@ int strv_extend_strv(char ***a, char **b, bool filter_duplicates) { p = strv_length(*a); q = strv_length(b); - t = reallocarray(*a, p + q + 1, sizeof(char *)); + if (p >= SIZE_MAX - q) + return -ENOMEM; + + t = reallocarray(*a, GREEDY_ALLOC_ROUND_UP(p + q + 1), sizeof(char *)); if (!t) return -ENOMEM; @@ -389,19 +392,18 @@ char *strv_join_prefix(char **l, const char *separator, const char *prefix) { int strv_push(char ***l, char *value) { char **c; - size_t n, m; + size_t n; if (!value) return 0; n = strv_length(*l); - /* Increase and check for overflow */ - m = n + 2; - if (m < n) + /* Check for overflow */ + if (n > SIZE_MAX-2) return -ENOMEM; - c = reallocarray(*l, m, sizeof(char*)); + c = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(n + 2), sizeof(char*)); if (!c) return -ENOMEM; @@ -414,19 +416,19 @@ int strv_push(char ***l, char *value) { int strv_push_pair(char ***l, char *a, char *b) { char **c; - size_t n, m; + size_t n; if (!a && !b) return 0; n = strv_length(*l); - /* increase and check for overflow */ - m = n + !!a + !!b + 1; - if (m < n) + /* Check for overflow */ + if (n > SIZE_MAX-3) return -ENOMEM; - c = reallocarray(*l, m, sizeof(char*)); + /* increase and check for overflow */ + c = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(n + !!a + !!b + 1), sizeof(char*)); if (!c) return -ENOMEM; @@ -856,8 +858,10 @@ int strv_extend_n(char ***l, const char *value, size_t n) { /* Adds the value n times to l */ k = strv_length(*l); + if (n >= SIZE_MAX - k) + return -ENOMEM; - nl = reallocarray(*l, k + n + 1, sizeof(char *)); + nl = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(k + n + 1), sizeof(char *)); if (!nl) return -ENOMEM; diff --git a/shared/systemd/src/basic/tmpfile-util.c b/shared/systemd/src/basic/tmpfile-util.c index d8a689e08d..83c69205e8 100644 --- a/shared/systemd/src/basic/tmpfile-util.c +++ b/shared/systemd/src/basic/tmpfile-util.c @@ -21,50 +21,60 @@ #include "tmpfile-util.h" #include "umask-util.h" -int fopen_temporary(const char *path, FILE **_f, char **_temp_path) { - FILE *f; - char *t; - int r, fd; +int fopen_temporary(const char *path, FILE **ret_f, char **ret_temp_path) { + _cleanup_fclose_ FILE *f = NULL; + _cleanup_free_ char *t = NULL; + _cleanup_close_ int fd = -1; + int r; - assert(path); - assert(_f); - assert(_temp_path); + if (path) { + r = tempfn_xxxxxx(path, NULL, &t); + if (r < 0) + return r; + } else { + const char *d; - r = tempfn_xxxxxx(path, NULL, &t); - if (r < 0) - return r; + r = tmp_dir(&d); + if (r < 0) + return r; + + t = path_join(d, "XXXXXX"); + if (!t) + return -ENOMEM; + } fd = mkostemp_safe(t); - if (fd < 0) { - free(t); + if (fd < 0) return -errno; - } /* This assumes that returned FILE object is short-lived and used within the same single-threaded * context and never shared externally, hence locking is not necessary. */ r = fdopen_unlocked(fd, "w", &f); if (r < 0) { - unlink(t); - free(t); - safe_close(fd); + (void) unlink(t); return r; } - *_f = f; - *_temp_path = t; + TAKE_FD(fd); + + if (ret_f) + *ret_f = TAKE_PTR(f); + + if (ret_temp_path) + *ret_temp_path = TAKE_PTR(t); return 0; } /* This is much like mkostemp() but is subject to umask(). */ int mkostemp_safe(char *pattern) { - _unused_ _cleanup_umask_ mode_t u = umask(0077); - int fd; + int fd = -1; /* avoid false maybe-uninitialized warning */ assert(pattern); - fd = mkostemp(pattern, O_CLOEXEC); + RUN_WITH_UMASK(0077) + fd = mkostemp(pattern, O_CLOEXEC); if (fd < 0) return -errno; diff --git a/src/systemd/src/libsystemd-network/sd-ipv4acd.c b/src/systemd/src/libsystemd-network/sd-ipv4acd.c index 3efa8170b1..9f69088dea 100644 --- a/src/systemd/src/libsystemd-network/sd-ipv4acd.c +++ b/src/systemd/src/libsystemd-network/sd-ipv4acd.c @@ -443,7 +443,7 @@ int sd_ipv4acd_is_running(sd_ipv4acd *acd) { return acd->state != IPV4ACD_STATE_INIT; } -int sd_ipv4acd_start(sd_ipv4acd *acd) { +int sd_ipv4acd_start(sd_ipv4acd *acd, bool reset_conflicts) { int r; assert_return(acd, -EINVAL); @@ -460,7 +460,9 @@ int sd_ipv4acd_start(sd_ipv4acd *acd) { safe_close(acd->fd); acd->fd = r; acd->defend_window = 0; - acd->n_conflict = 0; + + if (reset_conflicts) + acd->n_conflict = 0; r = sd_event_add_io(acd->event, &acd->receive_message_event_source, acd->fd, EPOLLIN, ipv4acd_on_packet, acd); if (r < 0) diff --git a/src/systemd/src/libsystemd-network/sd-ipv4ll.c b/src/systemd/src/libsystemd-network/sd-ipv4ll.c index 2d17b4fe81..a610546c4f 100644 --- a/src/systemd/src/libsystemd-network/sd-ipv4ll.c +++ b/src/systemd/src/libsystemd-network/sd-ipv4ll.c @@ -243,7 +243,7 @@ static int ipv4ll_start_internal(sd_ipv4ll *ll, bool reset_generation) { picked_address = true; } - r = sd_ipv4acd_start(ll->acd); + r = sd_ipv4acd_start(ll->acd, reset_generation); if (r < 0) { /* We couldn't start? If so, let's forget the picked address again, the user might make a change and diff --git a/src/systemd/src/libsystemd/sd-event/event-source.h b/src/systemd/src/libsystemd/sd-event/event-source.h index 99ab8fc169..08eb9b6a61 100644 --- a/src/systemd/src/libsystemd/sd-event/event-source.h +++ b/src/systemd/src/libsystemd/sd-event/event-source.h @@ -34,7 +34,7 @@ typedef enum EventSourceType { * we know how to dispatch it */ typedef enum WakeupType { WAKEUP_NONE, - WAKEUP_EVENT_SOURCE, + WAKEUP_EVENT_SOURCE, /* either I/O or pidfd wakeup */ WAKEUP_CLOCK_DATA, WAKEUP_SIGNAL_DATA, WAKEUP_INOTIFY_DATA, @@ -96,6 +96,12 @@ struct sd_event_source { siginfo_t siginfo; pid_t pid; int options; + int pidfd; + bool registered:1; /* whether the pidfd is registered in the epoll */ + bool pidfd_owned:1; /* close pidfd when event source is freed */ + bool process_owned:1; /* kill+reap process when event source is freed */ + bool exited:1; /* true if process exited (i.e. if there's value in SIGKILLing it if we want to get rid of it) */ + bool waited:1; /* true if process was waited for (i.e. if there's value in waitid(P_PID)'ing it if we want to get rid of it) */ } child; struct { sd_event_handler_t callback; diff --git a/src/systemd/src/libsystemd/sd-event/sd-event.c b/src/systemd/src/libsystemd/sd-event/sd-event.c index 7c4566e342..8ffaa75d51 100644 --- a/src/systemd/src/libsystemd/sd-event/sd-event.c +++ b/src/systemd/src/libsystemd/sd-event/sd-event.c @@ -11,6 +11,7 @@ #include "sd-id128.h" #include "alloc-util.h" +#include "env-util.h" #include "event-source.h" #include "fd-util.h" #include "fs-util.h" @@ -30,6 +31,14 @@ #define DEFAULT_ACCURACY_USEC (250 * USEC_PER_MSEC) +static bool EVENT_SOURCE_WATCH_PIDFD(sd_event_source *s) { + /* Returns true if this is a PID event source and can be implemented by watching EPOLLIN */ + return s && + s->type == SOURCE_CHILD && + s->child.pidfd >= 0 && + s->child.options == WEXITED; +} + static const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX] = { [SOURCE_IO] = "io", [SOURCE_TIME_REALTIME] = "realtime", @@ -358,8 +367,6 @@ static bool event_pid_changed(sd_event *e) { } static void source_io_unregister(sd_event_source *s) { - int r; - assert(s); assert(s->type == SOURCE_IO); @@ -369,8 +376,7 @@ static void source_io_unregister(sd_event_source *s) { if (!s->io.registered) return; - r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL); - if (r < 0) + if (epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL) < 0) log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll: %m", strna(s->description), event_source_type_to_string(s->type)); @@ -406,6 +412,51 @@ static int source_io_register( return 0; } +static void source_child_pidfd_unregister(sd_event_source *s) { + assert(s); + assert(s->type == SOURCE_CHILD); + + if (event_pid_changed(s->event)) + return; + + if (!s->child.registered) + return; + + if (EVENT_SOURCE_WATCH_PIDFD(s)) + if (epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->child.pidfd, NULL) < 0) + log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll: %m", + strna(s->description), event_source_type_to_string(s->type)); + + s->child.registered = false; +} + +static int source_child_pidfd_register(sd_event_source *s, int enabled) { + int r; + + assert(s); + assert(s->type == SOURCE_CHILD); + assert(enabled != SD_EVENT_OFF); + + if (EVENT_SOURCE_WATCH_PIDFD(s)) { + struct epoll_event ev; + + ev = (struct epoll_event) { + .events = EPOLLIN | (enabled == SD_EVENT_ONESHOT ? EPOLLONESHOT : 0), + .data.ptr = s, + }; + + if (s->child.registered) + r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_MOD, s->child.pidfd, &ev); + else + r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_ADD, s->child.pidfd, &ev); + if (r < 0) + return -errno; + } + + s->child.registered = true; + return 0; +} + static clockid_t event_source_type_to_clock(EventSourceType t) { switch (t) { @@ -616,9 +667,8 @@ static void event_gc_signal_data(sd_event *e, const int64_t *priority, int sig) assert(e); - /* Rechecks if the specified signal is still something we are - * interested in. If not, we'll unmask it, and possibly drop - * the signalfd for it. */ + /* Rechecks if the specified signal is still something we are interested in. If not, we'll unmask it, + * and possibly drop the signalfd for it. */ if (sig == SIGCHLD && e->n_enabled_child_sources > 0) @@ -709,9 +759,13 @@ static void source_disconnect(sd_event_source *s) { } (void) hashmap_remove(s->event->child_sources, PID_TO_PTR(s->child.pid)); - event_gc_signal_data(s->event, &s->priority, SIGCHLD); } + if (EVENT_SOURCE_WATCH_PIDFD(s)) + source_child_pidfd_unregister(s); + else + event_gc_signal_data(s->event, &s->priority, SIGCHLD); + break; case SOURCE_DEFER: @@ -792,6 +846,44 @@ static void source_free(sd_event_source *s) { if (s->type == SOURCE_IO && s->io.owned) s->io.fd = safe_close(s->io.fd); + if (s->type == SOURCE_CHILD) { + /* Eventually the kernel will do this automatically for us, but for now let's emulate this (unreliably) in userspace. */ + + if (s->child.process_owned) { + + if (!s->child.exited) { + bool sent = false; + + if (s->child.pidfd >= 0) { + if (pidfd_send_signal(s->child.pidfd, SIGKILL, NULL, 0) < 0) { + if (errno == ESRCH) /* Already dead */ + sent = true; + else if (!ERRNO_IS_NOT_SUPPORTED(errno)) + log_debug_errno(errno, "Failed to kill process " PID_FMT " via pidfd_send_signal(), re-trying via kill(): %m", + s->child.pid); + } else + sent = true; + } + + if (!sent) + if (kill(s->child.pid, SIGKILL) < 0) + if (errno != ESRCH) /* Already dead */ + log_debug_errno(errno, "Failed to kill process " PID_FMT " via kill(), ignoring: %m", + s->child.pid); + } + + if (!s->child.waited) { + siginfo_t si = {}; + + /* Reap the child if we can */ + (void) waitid(P_PID, s->child.pid, &si, WEXITED); + } + } + + if (s->child.pidfd_owned) + s->child.pidfd = safe_close(s->child.pidfd); + } + if (s->destroy_callback) s->destroy_callback(s->userdata); @@ -1076,7 +1168,6 @@ _public_ int sd_event_add_signal( _cleanup_(source_freep) sd_event_source *s = NULL; struct signal_data *d; - sigset_t ss; int r; assert_return(e, -EINVAL); @@ -1088,11 +1179,10 @@ _public_ int sd_event_add_signal( if (!callback) callback = signal_exit_callback; - r = pthread_sigmask(SIG_SETMASK, NULL, &ss); - if (r != 0) - return -r; - - if (!sigismember(&ss, sig)) + r = signal_is_blocked(sig); + if (r < 0) + return r; + if (r == 0) return -EBUSY; if (!e->signal_sources) { @@ -1126,7 +1216,11 @@ _public_ int sd_event_add_signal( return 0; } -#endif /* NM_IGNORED */ + +static bool shall_use_pidfd(void) { + /* Mostly relevant for debugging, i.e. this is used in test-event.c to test the event loop once with and once without pidfd */ + return getenv_bool_secure("SYSTEMD_PIDFD") != 0; +} _public_ int sd_event_add_child( sd_event *e, @@ -1148,6 +1242,20 @@ _public_ int sd_event_add_child( assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); + if (e->n_enabled_child_sources == 0) { + /* Caller must block SIGCHLD before using us to watch children, even if pidfd is available, + * for compatibility with pre-pidfd and because we don't want the reap the child processes + * ourselves, i.e. call waitid(), and don't want Linux' default internal logic for that to + * take effect. + * + * (As an optimization we only do this check on the first child event source created.) */ + r = signal_is_blocked(SIGCHLD); + if (r < 0) + return r; + if (r == 0) + return -EBUSY; + } + r = hashmap_ensure_allocated(&e->child_sources, NULL); if (r < 0) return r; @@ -1159,32 +1267,147 @@ _public_ int sd_event_add_child( if (!s) return -ENOMEM; + s->wakeup = WAKEUP_EVENT_SOURCE; s->child.pid = pid; s->child.options = options; s->child.callback = callback; s->userdata = userdata; s->enabled = SD_EVENT_ONESHOT; + /* We always take a pidfd here if we can, even if we wait for anything else than WEXITED, so that we + * pin the PID, and make regular waitid() handling race-free. */ + + if (shall_use_pidfd()) { + s->child.pidfd = pidfd_open(s->child.pid, 0); + if (s->child.pidfd < 0) { + /* Propagate errors unless the syscall is not supported or blocked */ + if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno)) + return -errno; + } else + s->child.pidfd_owned = true; /* If we allocate the pidfd we own it by default */ + } else + s->child.pidfd = -1; + r = hashmap_put(e->child_sources, PID_TO_PTR(pid), s); if (r < 0) return r; e->n_enabled_child_sources++; - r = event_make_signal_data(e, SIGCHLD, NULL); - if (r < 0) { - e->n_enabled_child_sources--; - return r; - } + if (EVENT_SOURCE_WATCH_PIDFD(s)) { + /* We have a pidfd and we only want to watch for exit */ + + r = source_child_pidfd_register(s, s->enabled); + if (r < 0) { + e->n_enabled_child_sources--; + return r; + } + } else { + /* We have no pidfd or we shall wait for some other event than WEXITED */ + + r = event_make_signal_data(e, SIGCHLD, NULL); + if (r < 0) { + e->n_enabled_child_sources--; + return r; + } - e->need_process_child = true; + e->need_process_child = true; + } if (ret) *ret = s; + TAKE_PTR(s); + return 0; +} + +_public_ int sd_event_add_child_pidfd( + sd_event *e, + sd_event_source **ret, + int pidfd, + int options, + sd_event_child_handler_t callback, + void *userdata) { + + + _cleanup_(source_freep) sd_event_source *s = NULL; + pid_t pid; + int r; + + assert_return(e, -EINVAL); + assert_return(e = event_resolve(e), -ENOPKG); + assert_return(pidfd >= 0, -EBADF); + assert_return(!(options & ~(WEXITED|WSTOPPED|WCONTINUED)), -EINVAL); + assert_return(options != 0, -EINVAL); + assert_return(callback, -EINVAL); + assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(!event_pid_changed(e), -ECHILD); + + if (e->n_enabled_child_sources == 0) { + r = signal_is_blocked(SIGCHLD); + if (r < 0) + return r; + if (r == 0) + return -EBUSY; + } + + r = hashmap_ensure_allocated(&e->child_sources, NULL); + if (r < 0) + return r; + + r = pidfd_get_pid(pidfd, &pid); + if (r < 0) + return r; + if (hashmap_contains(e->child_sources, PID_TO_PTR(pid))) + return -EBUSY; + + s = source_new(e, !ret, SOURCE_CHILD); + if (!s) + return -ENOMEM; + + s->wakeup = WAKEUP_EVENT_SOURCE; + s->child.pidfd = pidfd; + s->child.pid = pid; + s->child.options = options; + s->child.callback = callback; + s->child.pidfd_owned = false; /* If we got the pidfd passed in we don't own it by default (similar to the IO fd case) */ + s->userdata = userdata; + s->enabled = SD_EVENT_ONESHOT; + + r = hashmap_put(e->child_sources, PID_TO_PTR(pid), s); + if (r < 0) + return r; + + e->n_enabled_child_sources++; + + if (EVENT_SOURCE_WATCH_PIDFD(s)) { + /* We only want to watch for WEXITED */ + + r = source_child_pidfd_register(s, s->enabled); + if (r < 0) { + e->n_enabled_child_sources--; + return r; + } + } else { + /* We shall wait for some other event than WEXITED */ + + r = event_make_signal_data(e, SIGCHLD, NULL); + if (r < 0) { + e->n_enabled_child_sources--; + return r; + } + + e->need_process_child = true; + } + + if (ret) + *ret = s; + + TAKE_PTR(s); return 0; } +#endif /* NM_IGNORED */ _public_ int sd_event_add_defer( sd_event *e, @@ -1769,7 +1992,7 @@ _public_ int sd_event_source_set_io_fd(sd_event_source *s, int fd) { return r; } - epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, saved_fd, NULL); + (void) epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, saved_fd, NULL); } return 0; @@ -2030,7 +2253,11 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { assert(s->event->n_enabled_child_sources > 0); s->event->n_enabled_child_sources--; - event_gc_signal_data(s->event, &s->priority, SIGCHLD); + if (EVENT_SOURCE_WATCH_PIDFD(s)) + source_child_pidfd_unregister(s); + else + event_gc_signal_data(s->event, &s->priority, SIGCHLD); + break; case SOURCE_EXIT: @@ -2104,12 +2331,25 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { s->enabled = m; - r = event_make_signal_data(s->event, SIGCHLD, NULL); - if (r < 0) { - s->enabled = SD_EVENT_OFF; - s->event->n_enabled_child_sources--; - event_gc_signal_data(s->event, &s->priority, SIGCHLD); - return r; + if (EVENT_SOURCE_WATCH_PIDFD(s)) { + /* yes, we have pidfd */ + + r = source_child_pidfd_register(s, s->enabled); + if (r < 0) { + s->enabled = SD_EVENT_OFF; + s->event->n_enabled_child_sources--; + return r; + } + } else { + /* no pidfd, or something other to watch for than WEXITED */ + + r = event_make_signal_data(s->event, SIGCHLD, NULL); + if (r < 0) { + s->enabled = SD_EVENT_OFF; + s->event->n_enabled_child_sources--; + event_gc_signal_data(s->event, &s->priority, SIGCHLD); + return r; + } } break; @@ -2232,6 +2472,98 @@ _public_ int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid) { return 0; } +_public_ int sd_event_source_get_child_pidfd(sd_event_source *s) { + assert_return(s, -EINVAL); + assert_return(s->type == SOURCE_CHILD, -EDOM); + assert_return(!event_pid_changed(s->event), -ECHILD); + + if (s->child.pidfd < 0) + return -EOPNOTSUPP; + + return s->child.pidfd; +} + +_public_ int sd_event_source_send_child_signal(sd_event_source *s, int sig, const siginfo_t *si, unsigned flags) { + assert_return(s, -EINVAL); + assert_return(s->type == SOURCE_CHILD, -EDOM); + assert_return(!event_pid_changed(s->event), -ECHILD); + assert_return(SIGNAL_VALID(sig), -EINVAL); + + /* If we already have seen indication the process exited refuse sending a signal early. This way we + * can be sure we don't accidentally kill the wrong process on PID reuse when pidfds are not + * available. */ + if (s->child.exited) + return -ESRCH; + + if (s->child.pidfd >= 0) { + siginfo_t copy; + + /* pidfd_send_signal() changes the siginfo_t argument. This is weird, let's hence copy the + * structure here */ + if (si) + copy = *si; + + if (pidfd_send_signal(s->child.pidfd, sig, si ? © : NULL, 0) < 0) { + /* Let's propagate the error only if the system call is not implemented or prohibited */ + if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno)) + return -errno; + } else + return 0; + } + + /* Flags are only supported for pidfd_send_signal(), not for rt_sigqueueinfo(), hence let's refuse + * this here. */ + if (flags != 0) + return -EOPNOTSUPP; + + if (si) { + /* We use rt_sigqueueinfo() only if siginfo_t is specified. */ + siginfo_t copy = *si; + + if (rt_sigqueueinfo(s->child.pid, sig, ©) < 0) + return -errno; + } else if (kill(s->child.pid, sig) < 0) + return -errno; + + return 0; +} + +_public_ int sd_event_source_get_child_pidfd_own(sd_event_source *s) { + assert_return(s, -EINVAL); + assert_return(s->type == SOURCE_CHILD, -EDOM); + + if (s->child.pidfd < 0) + return -EOPNOTSUPP; + + return s->child.pidfd_owned; +} + +_public_ int sd_event_source_set_child_pidfd_own(sd_event_source *s, int own) { + assert_return(s, -EINVAL); + assert_return(s->type == SOURCE_CHILD, -EDOM); + + if (s->child.pidfd < 0) + return -EOPNOTSUPP; + + s->child.pidfd_owned = own; + return 0; +} + +_public_ int sd_event_source_get_child_process_own(sd_event_source *s) { + assert_return(s, -EINVAL); + assert_return(s->type == SOURCE_CHILD, -EDOM); + + return s->child.process_owned; +} + +_public_ int sd_event_source_set_child_process_own(sd_event_source *s, int own) { + assert_return(s, -EINVAL); + assert_return(s->type == SOURCE_CHILD, -EDOM); + + s->child.process_owned = own; + return 0; +} + _public_ int sd_event_source_get_inotify_mask(sd_event_source *s, uint32_t *mask) { assert_return(s, -EINVAL); assert_return(mask, -EINVAL); @@ -2542,6 +2874,12 @@ static int process_child(sd_event *e) { if (s->enabled == SD_EVENT_OFF) continue; + if (s->child.exited) + continue; + + if (EVENT_SOURCE_WATCH_PIDFD(s)) /* There's a usable pidfd known for this event source? then don't waitid() for it here */ + continue; + zero(s->child.siginfo); r = waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG | (s->child.options & WEXITED ? WNOWAIT : 0) | s->child.options); @@ -2551,6 +2889,9 @@ static int process_child(sd_event *e) { if (s->child.siginfo.si_pid != 0) { bool zombie = IN_SET(s->child.siginfo.si_code, CLD_EXITED, CLD_KILLED, CLD_DUMPED); + if (zombie) + s->child.exited = true; + if (!zombie && (s->child.options & WEXITED)) { /* If the child isn't dead then let's * immediately remove the state change @@ -2570,6 +2911,33 @@ static int process_child(sd_event *e) { return 0; } +static int process_pidfd(sd_event *e, sd_event_source *s, uint32_t revents) { + assert(e); + assert(s); + assert(s->type == SOURCE_CHILD); + + if (s->pending) + return 0; + + if (s->enabled == SD_EVENT_OFF) + return 0; + + if (!EVENT_SOURCE_WATCH_PIDFD(s)) + return 0; + + zero(s->child.siginfo); + if (waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG | WNOWAIT | s->child.options) < 0) + return -errno; + + if (s->child.siginfo.si_pid == 0) + return 0; + + if (IN_SET(s->child.siginfo.si_code, CLD_EXITED, CLD_KILLED, CLD_DUMPED)) + s->child.exited = true; + + return source_set_pending(s, true); +} + static int process_signal(sd_event *e, struct signal_data *d, uint32_t events) { bool read_one = false; int r; @@ -2854,8 +3222,10 @@ static int source_dispatch(sd_event_source *s) { r = s->child.callback(s, &s->child.siginfo, s->userdata); /* Now, reap the PID for good. */ - if (zombie) + if (zombie) { (void) waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG|WEXITED); + s->child.waited = true; + } break; } @@ -3056,6 +3426,11 @@ _public_ int sd_event_prepare(sd_event *e) { assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(e->state == SD_EVENT_INITIAL, -EBUSY); + /* Let's check that if we are a default event loop we are executed in the correct thread. We only do + * this check here once, since gettid() is typically not cached, and thus want to minimize + * syscalls */ + assert_return(!e->default_event_ptr || e->tid == gettid(), -EREMOTEIO); + if (e->exit_requested) goto pending; @@ -3151,12 +3526,33 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) { switch (*t) { - case WAKEUP_EVENT_SOURCE: - r = process_io(e, ev_queue[i].data.ptr, ev_queue[i].events); + case WAKEUP_EVENT_SOURCE: { + sd_event_source *s = ev_queue[i].data.ptr; + + assert(s); + + switch (s->type) { + + case SOURCE_IO: + r = process_io(e, s, ev_queue[i].events); + break; + + case SOURCE_CHILD: + r = process_pidfd(e, s, ev_queue[i].events); + break; + + default: + assert_not_reached("Unexpected event source type"); + } + break; + } case WAKEUP_CLOCK_DATA: { struct clock_data *d = ev_queue[i].data.ptr; + + assert(d); + r = flush_timer(e, d->fd, ev_queue[i].events, &d->next); break; } @@ -3481,7 +3877,7 @@ _public_ int sd_event_set_watchdog(sd_event *e, int b) { } else { if (e->watchdog_fd >= 0) { - epoll_ctl(e->epoll_fd, EPOLL_CTL_DEL, e->watchdog_fd, NULL); + (void) epoll_ctl(e->epoll_fd, EPOLL_CTL_DEL, e->watchdog_fd, NULL); e->watchdog_fd = safe_close(e->watchdog_fd); } } diff --git a/src/systemd/src/libsystemd/sd-id128/id128-util.c b/src/systemd/src/libsystemd/sd-id128/id128-util.c index f8f0883caf..11ae9037a3 100644 --- a/src/systemd/src/libsystemd/sd-id128/id128-util.c +++ b/src/systemd/src/libsystemd/sd-id128/id128-util.c @@ -14,7 +14,7 @@ #include "stdio-util.h" #if 0 /* NM_IGNORED */ -char *id128_to_uuid_string(sd_id128_t id, char s[37]) { +char *id128_to_uuid_string(sd_id128_t id, char s[static ID128_UUID_STRING_MAX]) { unsigned n, k = 0; assert(s); diff --git a/src/systemd/src/libsystemd/sd-id128/id128-util.h b/src/systemd/src/libsystemd/sd-id128/id128-util.h index 82a69a77f3..fe0149a8aa 100644 --- a/src/systemd/src/libsystemd/sd-id128/id128-util.h +++ b/src/systemd/src/libsystemd/sd-id128/id128-util.h @@ -8,7 +8,9 @@ #include "hash-funcs.h" #include "macro.h" -char *id128_to_uuid_string(sd_id128_t id, char s[37]); +#define ID128_UUID_STRING_MAX 37 + +char *id128_to_uuid_string(sd_id128_t id, char s[static ID128_UUID_STRING_MAX]); bool id128_is_valid(const char *s) _pure_; diff --git a/src/systemd/src/systemd/sd-event.h b/src/systemd/src/systemd/sd-event.h index b14c92697b..2ec726a897 100644 --- a/src/systemd/src/systemd/sd-event.h +++ b/src/systemd/src/systemd/sd-event.h @@ -23,6 +23,7 @@ #include <sys/inotify.h> #include <sys/signalfd.h> #include <sys/types.h> +#include <sys/wait.h> #include <time.h> #include "_sd-common.h" @@ -89,6 +90,7 @@ int sd_event_add_io(sd_event *e, sd_event_source **s, int fd, uint32_t events, s int sd_event_add_time(sd_event *e, sd_event_source **s, clockid_t clock, uint64_t usec, uint64_t accuracy, sd_event_time_handler_t callback, void *userdata); int sd_event_add_signal(sd_event *e, sd_event_source **s, int sig, sd_event_signal_handler_t callback, void *userdata); int sd_event_add_child(sd_event *e, sd_event_source **s, pid_t pid, int options, sd_event_child_handler_t callback, void *userdata); +int sd_event_add_child_pidfd(sd_event *e, sd_event_source **s, int pidfd, int options, sd_event_child_handler_t callback, void *userdata); int sd_event_add_inotify(sd_event *e, sd_event_source **s, const char *path, uint32_t mask, sd_event_inotify_handler_t callback, void *userdata); int sd_event_add_defer(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata); int sd_event_add_post(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata); @@ -141,6 +143,16 @@ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec); int sd_event_source_get_time_clock(sd_event_source *s, clockid_t *clock); int sd_event_source_get_signal(sd_event_source *s); int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid); +int sd_event_source_get_child_pidfd(sd_event_source *s); +int sd_event_source_get_child_pidfd_own(sd_event_source *s); +int sd_event_source_set_child_pidfd_own(sd_event_source *s, int own); +int sd_event_source_get_child_process_own(sd_event_source *s); +int sd_event_source_set_child_process_own(sd_event_source *s, int own); +#if defined _GNU_SOURCE || (defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 199309L) +int sd_event_source_send_child_signal(sd_event_source *s, int sig, const siginfo_t *si, unsigned flags); +#else +int sd_event_source_send_child_signal(sd_event_source *s, int sig, const void *si, unsigned flags); +#endif int sd_event_source_get_inotify_mask(sd_event_source *s, uint32_t *ret); int sd_event_source_set_destroy_callback(sd_event_source *s, sd_event_destroy_t callback); int sd_event_source_get_destroy_callback(sd_event_source *s, sd_event_destroy_t *ret); diff --git a/src/systemd/src/systemd/sd-ipv4acd.h b/src/systemd/src/systemd/sd-ipv4acd.h index 039ed3c7f2..ebf723fc22 100644 --- a/src/systemd/src/systemd/sd-ipv4acd.h +++ b/src/systemd/src/systemd/sd-ipv4acd.h @@ -20,6 +20,7 @@ #include <net/ethernet.h> #include <netinet/in.h> +#include <stdbool.h> #include "sd-event.h" @@ -44,7 +45,7 @@ int sd_ipv4acd_set_mac(sd_ipv4acd *acd, const struct ether_addr *addr); int sd_ipv4acd_set_ifindex(sd_ipv4acd *acd, int interface_index); int sd_ipv4acd_set_address(sd_ipv4acd *acd, const struct in_addr *address); int sd_ipv4acd_is_running(sd_ipv4acd *acd); -int sd_ipv4acd_start(sd_ipv4acd *acd); +int sd_ipv4acd_start(sd_ipv4acd *acd, bool reset_conflicts); int sd_ipv4acd_stop(sd_ipv4acd *acd); sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *acd); sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *acd); |