libc,shared: detect newer library symbols at runtime
For libc syscall wrappers (pidfd_open, fsopen, openat2, etc.) we previously gated the calls behind build-time HAVE_* checks. Replace these with shim functions in src/libc/ that fall back to the raw syscall at runtime when the loaded glibc lacks the symbol. The infrastructure lives in src/libc/libc-shim.h: DEFINE_SYSCALL_SHIM falls back to a direct syscall, DEFINE_LIBC_SHIM returns ENOSYS (for posix_spawn-family helpers that have no corresponding syscall), and DEFINE_LIBC_ERRNO_SHIM sets errno=ENOSYS and returns -1 (for read/write-style helpers). The weak reference to the libc symbol is bound via __asm__(\"name\") rename so the bare libc identifier never appears as a C token — this avoids both #undef boilerplate against override-header redirects and the resulting -Wredundant-decls warning. Drop the corresponding cc.has_function() loop from meson.build. For optional libraries (libcryptsetup, libdw, libarchive), drop the per-symbol HAVE_* checks. Always declare the prototypes, suppressing the redundant-decl warnings via DISABLE_WARNING_REDUNDANT_DECLS and NOLINT, and resolve the symbols after the main dlopen via a new DLSYM_OPTIONAL() helper that only assigns on success. libcryptsetup's crypt_set_keyring_to_link / crypt_token_set_external_path and libarchive's *_is_set wrappers use fallback functions as their pointer initializers (returning -ENOSYS and 0 respectively), so call sites can invoke the symbol unconditionally and just check for -ENOSYS where the \"not supported\" distinction matters. The same shim treatment applies to pidfd_spawn / posix_spawnattr_setcgroup_np (src/libc/spawn.c) and epoll_pwait2 (src/libc/epoll.c), with corresponding override headers in src/include/override/spawn.h and src/include/override/sys/epoll.h. posix_spawn_wrapper() in process-util.c and epoll_wait_usec() in sd-event.c now detect ENOSYS in the return value instead of checking the function pointer, falling back to plain posix_spawn() and epoll_wait() respectively. coredump-config and coredump-submit get a dlopen_dw_has_dwfl_set_sysroot() helper. The kexec arch gate now uses defined(__NR_kexec_file_load) directly; pidfd.h uses __has_include_next() to decide whether to pull in glibc's header. This lets binaries built against newer glibc / libcryptsetup / libdw / libarchive headers still load and run on older targets where these symbols are absent.
This commit is contained in:
@@ -3,15 +3,15 @@
|
||||
|
||||
#include_next <stdio.h>
|
||||
|
||||
#if !HAVE_RENAMEAT2
|
||||
#ifndef RENAME_NOREPLACE
|
||||
# define RENAME_NOREPLACE (1 << 0)
|
||||
# define RENAME_EXCHANGE (1 << 1)
|
||||
# define RENAME_WHITEOUT (1 << 2)
|
||||
|
||||
int missing_renameat2(int __oldfd, const char *__old, int __newfd, const char *__new, unsigned __flags);
|
||||
# define renameat2 missing_renameat2
|
||||
#endif
|
||||
|
||||
int renameat2_shim(int __oldfd, const char *__old, int __newfd, const char *__new, unsigned __flags);
|
||||
#define renameat2 renameat2_shim
|
||||
|
||||
/* When a stream is opened read-only under glibc, fputs() and friends fail with EBADF. However, they
|
||||
* succeed under musl. We rely on the glibc behavior in the code base. The following _check_writable()
|
||||
* functions first check if the passed stream is writable, and refuse to write with EBADF if not. */
|
||||
|
||||
@@ -27,7 +27,5 @@
|
||||
|
||||
/* Defined since glibc-2.42.
|
||||
* Supported since kernel v5.6 (fddb5d430ad9fa91b49b1d34d0202ffe2fa0e179). */
|
||||
#if !HAVE_OPENAT2
|
||||
int missing_openat2(int dfd, const char *filename, const struct open_how *how, size_t usize);
|
||||
# define openat2 missing_openat2
|
||||
#endif
|
||||
int openat2_shim(int dfd, const char *filename, const struct open_how *how, size_t usize);
|
||||
#define openat2 openat2_shim
|
||||
|
||||
@@ -51,10 +51,8 @@ int __clone2(int (*fn)(void *), void *stack_base, size_t stack_size, int flags,
|
||||
|
||||
/* Defined since glibc-2.41.
|
||||
* Supported since kernel 3.14 (e6cfc0295c7d51b008999a8b13a44fb43f8685ea). */
|
||||
#if !HAVE_SCHED_SETATTR
|
||||
int missing_sched_setattr(pid_t pid, struct sched_attr *attr, unsigned flags);
|
||||
# define sched_setattr missing_sched_setattr
|
||||
#endif
|
||||
int sched_setattr_shim(pid_t pid, struct sched_attr *attr, unsigned flags);
|
||||
#define sched_setattr sched_setattr_shim
|
||||
|
||||
/* f0e1a0643a59bf1f922fa209cec86a170b784f3f (6.12),
|
||||
* defined in sched.h in glibc since glibc-2.41. */
|
||||
|
||||
@@ -3,7 +3,5 @@
|
||||
|
||||
#include_next <signal.h> /* IWYU pragma: export */
|
||||
|
||||
#if !HAVE_RT_TGSIGQUEUEINFO
|
||||
int missing_rt_tgsigqueueinfo(pid_t tgid, pid_t tid, int sig, siginfo_t *info);
|
||||
# define rt_tgsigqueueinfo missing_rt_tgsigqueueinfo
|
||||
#endif
|
||||
int rt_tgsigqueueinfo_shim(pid_t tgid, pid_t tid, int sig, siginfo_t *info);
|
||||
#define rt_tgsigqueueinfo rt_tgsigqueueinfo_shim
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include_next <spawn.h> /* IWYU pragma: export */
|
||||
|
||||
/* pidfd_spawn() and posix_spawnattr_setcgroup_np() were added in glibc 2.39. Redirect to shims that
|
||||
* return ENOSYS at runtime when the libc symbols aren't available, so callers don't need to worry
|
||||
* about the libc version. */
|
||||
int pidfd_spawn_shim(pid_t *restrict pidfd, const char *restrict path,
|
||||
const posix_spawn_file_actions_t *restrict file_actions,
|
||||
const posix_spawnattr_t *restrict attrp,
|
||||
char *const argv[restrict], char *const envp[restrict]);
|
||||
#define pidfd_spawn pidfd_spawn_shim
|
||||
|
||||
int posix_spawnattr_setcgroup_np_shim(posix_spawnattr_t *attr, int cgroup);
|
||||
#define posix_spawnattr_setcgroup_np posix_spawnattr_setcgroup_np_shim
|
||||
|
||||
/* Defined in <spawn.h> since glibc 2.39. */
|
||||
#ifndef POSIX_SPAWN_SETCGROUP
|
||||
# define POSIX_SPAWN_SETCGROUP 0x100
|
||||
#endif
|
||||
@@ -5,7 +5,5 @@
|
||||
#include <stddef.h>
|
||||
|
||||
/* Supported since kernel v3.18 (749730ce42a2121e1c88350d69478bff3994b10a). */
|
||||
#if !HAVE_BPF
|
||||
int missing_bpf(int cmd, union bpf_attr *attr, size_t size);
|
||||
# define bpf missing_bpf
|
||||
#endif
|
||||
int bpf_shim(int cmd, union bpf_attr *attr, size_t size);
|
||||
#define bpf bpf_shim
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include_next <sys/epoll.h> /* IWYU pragma: export */
|
||||
|
||||
/* epoll_pwait2() was added to glibc 2.35. Redirect to a shim that sets errno=ENOSYS at runtime when
|
||||
* the libc symbol isn't available, so callers don't need to worry about the libc version. */
|
||||
int epoll_pwait2_shim(int fd, struct epoll_event *events, int maxevents,
|
||||
const struct timespec *timeout, const sigset_t *sigmask);
|
||||
#define epoll_pwait2 epoll_pwait2_shim
|
||||
@@ -3,12 +3,8 @@
|
||||
|
||||
#include <linux/ioprio.h> /* IWYU pragma: export */
|
||||
|
||||
#if !HAVE_IOPRIO_GET
|
||||
int missing_ioprio_get(int which, int who);
|
||||
# define ioprio_get missing_ioprio_get
|
||||
#endif
|
||||
int ioprio_get_shim(int which, int who);
|
||||
#define ioprio_get ioprio_get_shim
|
||||
|
||||
#if !HAVE_IOPRIO_SET
|
||||
int missing_ioprio_set(int which, int who, int ioprio);
|
||||
# define ioprio_set missing_ioprio_set
|
||||
#endif
|
||||
int ioprio_set_shim(int which, int who, int ioprio);
|
||||
#define ioprio_set ioprio_set_shim
|
||||
|
||||
@@ -5,7 +5,5 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
/* Supported since kernel v3.5 (d97b46a64674a267bc41c9e16132ee2a98c3347d). */
|
||||
#if !HAVE_KCMP
|
||||
int missing_kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2);
|
||||
# define kcmp missing_kcmp
|
||||
#endif
|
||||
int kcmp_shim(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2);
|
||||
#define kcmp kcmp_shim
|
||||
|
||||
@@ -6,11 +6,9 @@
|
||||
|
||||
/* Supported since kernel v3.17 (cb1052581e2bddd6096544f3f944f4e7fdad4c4f).
|
||||
* Not available on all architectures. */
|
||||
#if HAVE_KEXEC_FILE_LOAD || defined __NR_kexec_file_load
|
||||
# if !HAVE_KEXEC_FILE_LOAD
|
||||
int missing_kexec_file_load(int kernel_fd, int initrd_fd, unsigned long cmdline_len, const char *cmdline, unsigned long flags);
|
||||
# define kexec_file_load missing_kexec_file_load
|
||||
# endif
|
||||
#ifdef __NR_kexec_file_load
|
||||
int kexec_file_load_shim(int kernel_fd, int initrd_fd, unsigned long cmdline_len, const char *cmdline, unsigned long flags);
|
||||
# define kexec_file_load kexec_file_load_shim
|
||||
# define HAVE_KEXEC_FILE_LOAD_SYSCALL 1
|
||||
#else
|
||||
# define HAVE_KEXEC_FILE_LOAD_SYSCALL 0
|
||||
|
||||
@@ -4,17 +4,11 @@
|
||||
#include <linux/keyctl.h> /* IWYU pragma: export */
|
||||
#include <stddef.h>
|
||||
|
||||
#if !HAVE_KEYCTL
|
||||
long missing_keyctl(int cmd, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5);
|
||||
# define keyctl missing_keyctl
|
||||
#endif
|
||||
long keyctl_shim(int cmd, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5);
|
||||
#define keyctl keyctl_shim
|
||||
|
||||
#if !HAVE_ADD_KEY
|
||||
key_serial_t missing_add_key(const char *type, const char *description, const void *payload, size_t plen, key_serial_t ringid);
|
||||
# define add_key missing_add_key
|
||||
#endif
|
||||
key_serial_t add_key_shim(const char *type, const char *description, const void *payload, size_t plen, key_serial_t ringid);
|
||||
#define add_key add_key_shim
|
||||
|
||||
#if !HAVE_REQUEST_KEY
|
||||
key_serial_t missing_request_key(const char *type, const char *description, const char *callout_info, key_serial_t destringid);
|
||||
# define request_key missing_request_key
|
||||
#endif
|
||||
key_serial_t request_key_shim(const char *type, const char *description, const char *callout_info, key_serial_t destringid);
|
||||
#define request_key request_key_shim
|
||||
|
||||
@@ -3,12 +3,8 @@
|
||||
|
||||
#include <linux/mempolicy.h> /* IWYU pragma: export */
|
||||
|
||||
#if !HAVE_SET_MEMPOLICY
|
||||
int missing_set_mempolicy(int mode, const unsigned long *nodemask, unsigned long maxnode);
|
||||
# define set_mempolicy missing_set_mempolicy
|
||||
#endif
|
||||
int set_mempolicy_shim(int mode, const unsigned long *nodemask, unsigned long maxnode);
|
||||
#define set_mempolicy set_mempolicy_shim
|
||||
|
||||
#if !HAVE_GET_MEMPOLICY
|
||||
int missing_get_mempolicy(int *mode, unsigned long *nodemask, unsigned long maxnode, void *addr, unsigned long flags);
|
||||
# define get_mempolicy missing_get_mempolicy
|
||||
#endif
|
||||
int get_mempolicy_shim(int *mode, unsigned long *nodemask, unsigned long maxnode, void *addr, unsigned long flags);
|
||||
#define get_mempolicy get_mempolicy_shim
|
||||
|
||||
@@ -39,56 +39,36 @@ extern int umount2(const char *__special_file, int __flags);
|
||||
/* Open the filesystem referenced by FS_NAME so it can be configured for mounting. */
|
||||
/* Defined since glibc-2.36.
|
||||
* Supported since kernel v5.2 (24dcb3d90a1f67fe08c68a004af37df059d74005). */
|
||||
#if HAVE_FSOPEN
|
||||
extern int fsopen(const char *__fs_name, unsigned int __flags);
|
||||
#else
|
||||
int missing_fsopen(const char *fsname, unsigned flags);
|
||||
# define fsopen missing_fsopen
|
||||
#endif
|
||||
int fsopen_shim(const char *fsname, unsigned flags);
|
||||
#define fsopen fsopen_shim
|
||||
|
||||
/* Create a mount representation for the FD created by fsopen using
|
||||
FLAGS with ATTR_FLAGS describing how the mount is to be performed. */
|
||||
/* Defined since glibc-2.36.
|
||||
* Supported since kernel v5.2 (93766fbd2696c2c4453dd8e1070977e9cd4e6b6d). */
|
||||
#if HAVE_FSMOUNT
|
||||
extern int fsmount(int __fd, unsigned int __flags, unsigned int __ms_flags);
|
||||
#else
|
||||
int missing_fsmount(int fd, unsigned flags, unsigned ms_flags);
|
||||
# define fsmount missing_fsmount
|
||||
#endif
|
||||
int fsmount_shim(int fd, unsigned flags, unsigned ms_flags);
|
||||
#define fsmount fsmount_shim
|
||||
|
||||
/* Add the mounted FROM_DFD referenced by FROM_PATHNAME filesystem returned
|
||||
by fsmount in the hierarchy in the place TO_DFD reference by TO_PATHNAME
|
||||
using FLAGS. */
|
||||
/* Defined since glibc-2.36.
|
||||
* Supported since kernel v5.2 (2db154b3ea8e14b04fee23e3fdfd5e9d17fbc6ae). */
|
||||
#if HAVE_MOVE_MOUNT
|
||||
extern int move_mount(int __from_dfd, const char *__from_pathname, int __to_dfd, const char *__to_pathname, unsigned int flags);
|
||||
#else
|
||||
int missing_move_mount(int from_dfd, const char *from_pathname, int to_dfd, const char *to_pathname, unsigned flags);
|
||||
# define move_mount missing_move_mount
|
||||
#endif
|
||||
int move_mount_shim(int from_dfd, const char *from_pathname, int to_dfd, const char *to_pathname, unsigned flags);
|
||||
#define move_mount move_mount_shim
|
||||
|
||||
/* Set parameters and trigger CMD action on the FD context. KEY, VALUE,
|
||||
and AUX are used depending ng of the CMD. */
|
||||
/* Defined since glibc-2.36.
|
||||
* Supported since kernel v5.2 (ecdab150fddb42fe6a739335257949220033b782). */
|
||||
#if HAVE_FSCONFIG
|
||||
extern int fsconfig(int __fd, unsigned int __cmd, const char *__key, const void *__value, int __aux);
|
||||
#else
|
||||
int missing_fsconfig(int fd, unsigned cmd, const char *key, const void *value, int aux);
|
||||
# define fsconfig missing_fsconfig
|
||||
#endif
|
||||
int fsconfig_shim(int fd, unsigned cmd, const char *key, const void *value, int aux);
|
||||
#define fsconfig fsconfig_shim
|
||||
|
||||
/* Open the mount point FILENAME in directory DFD using FLAGS. */
|
||||
/* Defined since glibc-2.36.
|
||||
* Supported since kernel v5.2 (a07b20004793d8926f78d63eb5980559f7813404). */
|
||||
#if HAVE_OPEN_TREE
|
||||
extern int open_tree(int __dfd, const char *__filename, unsigned int __flags);
|
||||
#else
|
||||
int missing_open_tree(int dfd, const char *filename, unsigned flags);
|
||||
# define open_tree missing_open_tree
|
||||
#endif
|
||||
int open_tree_shim(int dfd, const char *filename, unsigned flags);
|
||||
#define open_tree open_tree_shim
|
||||
|
||||
/* Change the mount properties of the mount or an entire mount tree. If
|
||||
PATH is a relative pathname, then it is interpreted relative to the
|
||||
@@ -97,18 +77,10 @@ int missing_open_tree(int dfd, const char *filename, unsigned flags);
|
||||
working directory of the calling process. */
|
||||
/* Defined since glibc-2.36.
|
||||
* Supported since kernel v5.12 (2a1867219c7b27f928e2545782b86daaf9ad50bd). */
|
||||
#if HAVE_MOUNT_SETATTR
|
||||
extern int mount_setattr(int __dfd, const char *__path, unsigned int __flags, struct mount_attr *__uattr, size_t __usize);
|
||||
#else
|
||||
int missing_mount_setattr(int dfd, const char *path, unsigned flags, struct mount_attr *attr, size_t size);
|
||||
# define mount_setattr missing_mount_setattr
|
||||
#endif
|
||||
int mount_setattr_shim(int dfd, const char *path, unsigned flags, struct mount_attr *attr, size_t size);
|
||||
#define mount_setattr mount_setattr_shim
|
||||
|
||||
/* Not defined in glibc yet as of glibc-2.41.
|
||||
* Supported since kernel v6.15 (c4a16820d90199409c9bf01c4f794e1e9e8d8fd8). */
|
||||
#if HAVE_OPEN_TREE_ATTR
|
||||
extern int open_tree_attr(int __dfd, const char *__filename, unsigned int __flags, struct mount_attr *__uattr, size_t __usize);
|
||||
#else
|
||||
int missing_open_tree_attr(int dfd, const char *filename, unsigned int flags, struct mount_attr *attr, size_t size);
|
||||
# define open_tree_attr missing_open_tree_attr
|
||||
#endif
|
||||
int open_tree_attr_shim(int dfd, const char *filename, unsigned int flags, struct mount_attr *attr, size_t size);
|
||||
#define open_tree_attr open_tree_attr_shim
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
/* since glibc-2.36 */
|
||||
#if HAVE_PIDFD_OPEN
|
||||
#include <features.h>
|
||||
|
||||
/* since glibc-2.36. Only descend into the next <sys/pidfd.h> on glibc — musl ships no such header,
|
||||
* and musl-gcc's -idirafter /usr/include would otherwise pull in glibc's copy (which depends on
|
||||
* __THROW and other glibc-isms) from the fallback path. */
|
||||
#if defined(__GLIBC__) && __has_include_next(<sys/pidfd.h>)
|
||||
#include_next <sys/pidfd.h> /* IWYU pragma: export */
|
||||
#endif
|
||||
|
||||
@@ -12,17 +16,13 @@
|
||||
|
||||
/* Defined since glibc-2.36.
|
||||
* Supported since kernel v5.3 (7615d9e1780e26e0178c93c55b73309a5dc093d7). */
|
||||
#if !HAVE_PIDFD_OPEN
|
||||
int missing_pidfd_open(pid_t pid, unsigned flags);
|
||||
# define pidfd_open missing_pidfd_open
|
||||
#endif
|
||||
int pidfd_open_shim(pid_t pid, unsigned flags);
|
||||
#define pidfd_open pidfd_open_shim
|
||||
|
||||
/* Defined since glibc-2.36.
|
||||
* Supported since kernel v5.1 (3eb39f47934f9d5a3027fe00d906a45fe3a15fad). */
|
||||
#if !HAVE_PIDFD_SEND_SIGNAL
|
||||
int missing_pidfd_send_signal(int fd, int sig, siginfo_t *info, unsigned flags);
|
||||
# define pidfd_send_signal missing_pidfd_send_signal
|
||||
#endif
|
||||
int pidfd_send_signal_shim(int fd, int sig, siginfo_t *info, unsigned flags);
|
||||
#define pidfd_send_signal pidfd_send_signal_shim
|
||||
|
||||
/* since glibc-2.41 */
|
||||
#ifndef PIDFS_IOCTL_MAGIC
|
||||
|
||||
@@ -4,7 +4,5 @@
|
||||
#include_next <sys/quota.h> /* IWYU pragma: export */
|
||||
|
||||
/* Supported since kernel v5.14 (64c2c2c62f92339b176ea24403d8db16db36f9e6). */
|
||||
#if !HAVE_QUOTACTL_FD
|
||||
int missing_quotactl_fd(int fd, int cmd, int id, void *addr);
|
||||
# define quotactl_fd missing_quotactl_fd
|
||||
#endif
|
||||
int quotactl_fd_shim(int fd, int cmd, int id, void *addr);
|
||||
#define quotactl_fd quotactl_fd_shim
|
||||
|
||||
@@ -4,7 +4,5 @@
|
||||
#include_next <sys/stat.h> /* IWYU pragma: export */
|
||||
|
||||
/* Supported since kernel v6.6 (78252deb023cf0879256fcfbafe37022c390762b). */
|
||||
#if !HAVE_FCHMODAT2
|
||||
int missing_fchmodat2(int dirfd, const char *path, mode_t mode, int flags);
|
||||
# define fchmodat2 missing_fchmodat2
|
||||
#endif
|
||||
int fchmodat2_shim(int dirfd, const char *path, mode_t mode, int flags);
|
||||
#define fchmodat2 fchmodat2_shim
|
||||
|
||||
@@ -8,13 +8,9 @@
|
||||
#include_next <sys/xattr.h> /* IWYU pragma: export */
|
||||
|
||||
/* Supported since kernel v6.13 (6140be90ec70c39fa844741ca3cc807dd0866394). */
|
||||
#if !HAVE_SETXATTRAT
|
||||
int missing_setxattrat(int fd, const char *path, int at_flags, const char *name, const struct xattr_args *args, size_t size);
|
||||
# define setxattrat missing_setxattrat
|
||||
#endif
|
||||
int setxattrat_shim(int fd, const char *path, int at_flags, const char *name, const struct xattr_args *args, size_t size);
|
||||
#define setxattrat setxattrat_shim
|
||||
|
||||
/* Supported since kernel v6.13 (6140be90ec70c39fa844741ca3cc807dd0866394). */
|
||||
#if !HAVE_REMOVEXATTRAT
|
||||
int missing_removexattrat(int fd, const char *path, int at_flags, const char *name);
|
||||
# define removexattrat missing_removexattrat
|
||||
#endif
|
||||
int removexattrat_shim(int fd, const char *path, int at_flags, const char *name);
|
||||
#define removexattrat removexattrat_shim
|
||||
|
||||
@@ -3,7 +3,5 @@
|
||||
|
||||
#include_next <unistd.h> /* IWYU pragma: export */
|
||||
|
||||
#if !HAVE_PIVOT_ROOT
|
||||
int missing_pivot_root(const char *new_root, const char *put_old);
|
||||
# define pivot_root missing_pivot_root
|
||||
#endif
|
||||
int pivot_root_shim(const char *new_root, const char *put_old);
|
||||
#define pivot_root pivot_root_shim
|
||||
|
||||
Reference in New Issue
Block a user