diff mbox series

linux: Add openat2 (BZ 31664)

Message ID 20240424173826.2507003-1-adhemerval.zanella@linaro.org
State Superseded
Headers show
Series linux: Add openat2 (BZ 31664) | expand

Commit Message

Adhemerval Zanella April 24, 2024, 5:38 p.m. UTC
It was added on Linux 5.6, as an extension of openat.  Different than
other open-like functions, the kernel only provides the LFS variant (so
files larger than 4GB always succeed, as other functions with offset
larger than off_t).  Similar to other open functions, the new symbol is
a cancellable entrypoint.

The test case added only stresses some of the syscalls provided
functionalities and it is based on an existent kernel self-test.  Since
the prototype does not use variadic arguments, there is no need to add a
fortify wrapper to catch wrong usages.

Checked on x86_64-linux-gnu.
---
 NEWS                                          |   4 +
 sysdeps/unix/sysv/linux/Makefile              |  14 +
 sysdeps/unix/sysv/linux/Versions              |   3 +
 sysdeps/unix/sysv/linux/aarch64/libc.abilist  |   1 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist    |   1 +
 sysdeps/unix/sysv/linux/arc/libc.abilist      |   1 +
 sysdeps/unix/sysv/linux/arm/be/libc.abilist   |   1 +
 sysdeps/unix/sysv/linux/arm/le/libc.abilist   |   1 +
 sysdeps/unix/sysv/linux/bits/fcntl-linux.h    |  22 ++
 sysdeps/unix/sysv/linux/bits/openat2.h        |  61 +++++
 sysdeps/unix/sysv/linux/csky/libc.abilist     |   1 +
 sysdeps/unix/sysv/linux/hppa/libc.abilist     |   1 +
 sysdeps/unix/sysv/linux/i386/libc.abilist     |   1 +
 .../sysv/linux/loongarch/lp64/libc.abilist    |   1 +
 .../sysv/linux/m68k/coldfire/libc.abilist     |   1 +
 .../unix/sysv/linux/m68k/m680x0/libc.abilist  |   1 +
 .../sysv/linux/microblaze/be/libc.abilist     |   1 +
 .../sysv/linux/microblaze/le/libc.abilist     |   1 +
 .../sysv/linux/mips/mips32/fpu/libc.abilist   |   1 +
 .../sysv/linux/mips/mips32/nofpu/libc.abilist |   1 +
 .../sysv/linux/mips/mips64/n32/libc.abilist   |   1 +
 .../sysv/linux/mips/mips64/n64/libc.abilist   |   1 +
 sysdeps/unix/sysv/linux/nios2/libc.abilist    |   1 +
 sysdeps/unix/sysv/linux/openat2.c             |  29 ++
 sysdeps/unix/sysv/linux/or1k/libc.abilist     |   1 +
 .../linux/powerpc/powerpc32/fpu/libc.abilist  |   1 +
 .../powerpc/powerpc32/nofpu/libc.abilist      |   1 +
 .../linux/powerpc/powerpc64/be/libc.abilist   |   1 +
 .../linux/powerpc/powerpc64/le/libc.abilist   |   1 +
 .../unix/sysv/linux/riscv/rv32/libc.abilist   |   1 +
 .../unix/sysv/linux/riscv/rv64/libc.abilist   |   1 +
 .../unix/sysv/linux/s390/s390-32/libc.abilist |   1 +
 .../unix/sysv/linux/s390/s390-64/libc.abilist |   1 +
 sysdeps/unix/sysv/linux/sh/be/libc.abilist    |   1 +
 sysdeps/unix/sysv/linux/sh/le/libc.abilist    |   1 +
 .../sysv/linux/sparc/sparc32/libc.abilist     |   1 +
 .../sysv/linux/sparc/sparc64/libc.abilist     |   1 +
 sysdeps/unix/sysv/linux/tst-openat2-consts.py |  63 +++++
 sysdeps/unix/sysv/linux/tst-openat2.c         | 259 ++++++++++++++++++
 .../unix/sysv/linux/x86_64/64/libc.abilist    |   1 +
 .../unix/sysv/linux/x86_64/x32/libc.abilist   |   1 +
 41 files changed, 488 insertions(+)
 create mode 100644 sysdeps/unix/sysv/linux/bits/openat2.h
 create mode 100644 sysdeps/unix/sysv/linux/openat2.c
 create mode 100755 sysdeps/unix/sysv/linux/tst-openat2-consts.py
 create mode 100644 sysdeps/unix/sysv/linux/tst-openat2.c

Comments

enh April 24, 2024, 5:42 p.m. UTC | #1
doesn't glibc worry about types like this, where the size can change?
that presents a problem for code passing those types around. do you
require that all the code in a process be compiled with the exact same
headers?

On Wed, Apr 24, 2024 at 10:38 AM Adhemerval Zanella
<adhemerval.zanella@linaro.org> wrote:
>
> It was added on Linux 5.6, as an extension of openat.  Different than
> other open-like functions, the kernel only provides the LFS variant (so
> files larger than 4GB always succeed, as other functions with offset
> larger than off_t).  Similar to other open functions, the new symbol is
> a cancellable entrypoint.
>
> The test case added only stresses some of the syscalls provided
> functionalities and it is based on an existent kernel self-test.  Since
> the prototype does not use variadic arguments, there is no need to add a
> fortify wrapper to catch wrong usages.
>
> Checked on x86_64-linux-gnu.
> ---
>  NEWS                                          |   4 +
>  sysdeps/unix/sysv/linux/Makefile              |  14 +
>  sysdeps/unix/sysv/linux/Versions              |   3 +
>  sysdeps/unix/sysv/linux/aarch64/libc.abilist  |   1 +
>  sysdeps/unix/sysv/linux/alpha/libc.abilist    |   1 +
>  sysdeps/unix/sysv/linux/arc/libc.abilist      |   1 +
>  sysdeps/unix/sysv/linux/arm/be/libc.abilist   |   1 +
>  sysdeps/unix/sysv/linux/arm/le/libc.abilist   |   1 +
>  sysdeps/unix/sysv/linux/bits/fcntl-linux.h    |  22 ++
>  sysdeps/unix/sysv/linux/bits/openat2.h        |  61 +++++
>  sysdeps/unix/sysv/linux/csky/libc.abilist     |   1 +
>  sysdeps/unix/sysv/linux/hppa/libc.abilist     |   1 +
>  sysdeps/unix/sysv/linux/i386/libc.abilist     |   1 +
>  .../sysv/linux/loongarch/lp64/libc.abilist    |   1 +
>  .../sysv/linux/m68k/coldfire/libc.abilist     |   1 +
>  .../unix/sysv/linux/m68k/m680x0/libc.abilist  |   1 +
>  .../sysv/linux/microblaze/be/libc.abilist     |   1 +
>  .../sysv/linux/microblaze/le/libc.abilist     |   1 +
>  .../sysv/linux/mips/mips32/fpu/libc.abilist   |   1 +
>  .../sysv/linux/mips/mips32/nofpu/libc.abilist |   1 +
>  .../sysv/linux/mips/mips64/n32/libc.abilist   |   1 +
>  .../sysv/linux/mips/mips64/n64/libc.abilist   |   1 +
>  sysdeps/unix/sysv/linux/nios2/libc.abilist    |   1 +
>  sysdeps/unix/sysv/linux/openat2.c             |  29 ++
>  sysdeps/unix/sysv/linux/or1k/libc.abilist     |   1 +
>  .../linux/powerpc/powerpc32/fpu/libc.abilist  |   1 +
>  .../powerpc/powerpc32/nofpu/libc.abilist      |   1 +
>  .../linux/powerpc/powerpc64/be/libc.abilist   |   1 +
>  .../linux/powerpc/powerpc64/le/libc.abilist   |   1 +
>  .../unix/sysv/linux/riscv/rv32/libc.abilist   |   1 +
>  .../unix/sysv/linux/riscv/rv64/libc.abilist   |   1 +
>  .../unix/sysv/linux/s390/s390-32/libc.abilist |   1 +
>  .../unix/sysv/linux/s390/s390-64/libc.abilist |   1 +
>  sysdeps/unix/sysv/linux/sh/be/libc.abilist    |   1 +
>  sysdeps/unix/sysv/linux/sh/le/libc.abilist    |   1 +
>  .../sysv/linux/sparc/sparc32/libc.abilist     |   1 +
>  .../sysv/linux/sparc/sparc64/libc.abilist     |   1 +
>  sysdeps/unix/sysv/linux/tst-openat2-consts.py |  63 +++++
>  sysdeps/unix/sysv/linux/tst-openat2.c         | 259 ++++++++++++++++++
>  .../unix/sysv/linux/x86_64/64/libc.abilist    |   1 +
>  .../unix/sysv/linux/x86_64/x32/libc.abilist   |   1 +
>  41 files changed, 488 insertions(+)
>  create mode 100644 sysdeps/unix/sysv/linux/bits/openat2.h
>  create mode 100644 sysdeps/unix/sysv/linux/openat2.c
>  create mode 100755 sysdeps/unix/sysv/linux/tst-openat2-consts.py
>  create mode 100644 sysdeps/unix/sysv/linux/tst-openat2.c
>
> diff --git a/NEWS b/NEWS
> index cf6078cf20..eaaa02cb4e 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -26,6 +26,10 @@ Major new features:
>    more extensive verification tests for AT_SECURE programs and not meant to
>    be a security feature.
>
> +* On Linux, the openat2 function has been added.  It is an extension of
> +  openat and provides a superset of its functionality.  It is supported only
> +  in LFS mode and as other open like it is a cancellable entrypoint.
> +
>  Deprecated and removed features, and other changes affecting compatibility:
>
>  * Architectures which use a 32-bit seconds-since-epoch field in struct
> diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
> index 415aa1f14d..4ae8ec6dc6 100644
> --- a/sysdeps/unix/sysv/linux/Makefile
> +++ b/sysdeps/unix/sysv/linux/Makefile
> @@ -133,6 +133,7 @@ sysdep_headers += \
>    bits/mman-linux.h \
>    bits/mman-map-flags-generic.h \
>    bits/mman-shared.h \
> +  bits/openat2.h \
>    bits/procfs-extra.h \
>    bits/procfs-id.h \
>    bits/procfs-prregset.h \
> @@ -591,6 +592,7 @@ sysdep_routines += \
>    internal_statvfs \
>    open64_nocancel \
>    open_nocancel \
> +  openat2 \
>    openat64_nocancel \
>    openat_nocancel \
>    pread64_nocancel \
> @@ -611,7 +613,19 @@ tests += \
>    tst-fallocate64 \
>    tst-getcwd-smallbuff \
>    tst-o_path-locks \
> +  tst-openat2 \
>    # tests
> +
> +tests-special += \
> +  $(objpfx)tst-openat2-consts.out \
> +  # tests-special
> +$(objpfx)tst-openat2-consts.out: ../sysdeps/unix/sysv/linux/tst-openat2-consts.py
> +       $(sysdeps-linux-python) \
> +         ../sysdeps/unix/sysv/linux/tst-openat2-consts.py \
> +           $(sysdeps-linux-python-cc) \
> +         < /dev/null > $@ 2>&1; $(evaluate-test)
> +$(objpfx)tst-openat2-consts.out: $(sysdeps-linux-python-deps)
> +
>  endif
>
>  ifeq ($(subdir),elf)
> diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions
> index 268ba1b6ac..65da2b617a 100644
> --- a/sysdeps/unix/sysv/linux/Versions
> +++ b/sysdeps/unix/sysv/linux/Versions
> @@ -328,6 +328,9 @@ libc {
>      posix_spawnattr_getcgroup_np;
>      posix_spawnattr_setcgroup_np;
>    }
> +  GLIBC_2.40 {
> +    openat2;
> +  }
>    GLIBC_PRIVATE {
>      # functions used in other libraries
>      __syscall_rt_sigqueueinfo;
> diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> index 68eeca1c08..0b9bd8ae62 100644
> --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> @@ -2748,3 +2748,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
>  GLIBC_2.39 stdc_trailing_zeros_ul F
>  GLIBC_2.39 stdc_trailing_zeros_ull F
>  GLIBC_2.39 stdc_trailing_zeros_us F
> +GLIBC_2.40 openat2 F
> diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> index 34c187b721..c0bd27d617 100644
> --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> @@ -3095,6 +3095,7 @@ GLIBC_2.4 wcstold F
>  GLIBC_2.4 wcstold_l F
>  GLIBC_2.4 wprintf F
>  GLIBC_2.4 wscanf F
> +GLIBC_2.40 openat2 F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
> index 916c18ea94..965438e7a7 100644
> --- a/sysdeps/unix/sysv/linux/arc/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
> @@ -2509,3 +2509,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
>  GLIBC_2.39 stdc_trailing_zeros_ul F
>  GLIBC_2.39 stdc_trailing_zeros_ull F
>  GLIBC_2.39 stdc_trailing_zeros_us F
> +GLIBC_2.40 openat2 F
> diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> index ea95de282a..e69ed8c903 100644
> --- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> @@ -2801,6 +2801,7 @@ GLIBC_2.4 xdrstdio_create F
>  GLIBC_2.4 xencrypt F
>  GLIBC_2.4 xprt_register F
>  GLIBC_2.4 xprt_unregister F
> +GLIBC_2.40 openat2 F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> index 1cdbc983e1..70fd425869 100644
> --- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> @@ -2798,6 +2798,7 @@ GLIBC_2.4 xdrstdio_create F
>  GLIBC_2.4 xencrypt F
>  GLIBC_2.4 xprt_register F
>  GLIBC_2.4 xprt_unregister F
> +GLIBC_2.40 openat2 F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
> index 628612b885..279aa2b8eb 100644
> --- a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
> +++ b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
> @@ -451,6 +451,28 @@ extern int name_to_handle_at (int __dfd, const char *__name,
>  extern int open_by_handle_at (int __mountdirfd, struct file_handle *__handle,
>                               int __flags);
>
> +#ifdef __has_include
> +# if __has_include ("linux/openat2.h")
> +#  include "linux/openat2.h"
> +#  define __glibc_has_open_how 1
> +# endif
> +#endif
> +
> +#include <bits/openat2.h>
> +
> +/* Similar to `openat' but the arguments are packed on HOW with the size
> +   USIZE.  If flags and mode from HOW are non-zero, then openat2 operates
> +   like openat.
> +
> +   Unlike openat2, unknown or invalid flags result in an error (EINVAL),
> +   rather than being ignored.  The mode must be zero unless one O_CREAT
> +   or O_TMPFILE are set.
> +
> +   The kernel does not support legacy non-LFS interface.  */
> +extern int openat2 (int __dfd, const char *__filename, struct open_how *__how,
> +                   size_t __usize)
> +     __nonnull ((2, 3));
> +
>  #endif /* use GNU */
>
>  __END_DECLS
> diff --git a/sysdeps/unix/sysv/linux/bits/openat2.h b/sysdeps/unix/sysv/linux/bits/openat2.h
> new file mode 100644
> index 0000000000..a07984dace
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/bits/openat2.h
> @@ -0,0 +1,61 @@
> +/* openat2 definition.  Linux specific.
> +   Copyright (C) 2024 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#ifndef        _FCNTL_H
> +# error "Never use <bits/openat2.h> directly; include <fcntl.h> instead."
> +#endif
> +
> +#ifndef __glibc_has_open_how
> +/* Arguments for how openat2 should open the target path.  */
> +struct open_how
> +{
> +  __uint64_t flags;
> +  __uint64_t mode;
> +  __uint64_t resolve;
> +};
> +#endif
> +
> +/* how->resolve flags for openat2. */
> +#ifndef RESOLVE_NO_XDEV
> +# define RESOLVE_NO_XDEV       0x01 /* Block mount-point crossings
> +                                       (includes bind-mounts).  */
> +#endif
> +#ifndef RESOLVE_NO_MAGICLINKS
> +# define RESOLVE_NO_MAGICLINKS 0x02 /* Block traversal through procfs-style
> +                                       "magic-links".  */
> +#endif
> +#ifndef RESOLVE_NO_SYMLINKS
> +# define RESOLVE_NO_SYMLINKS   0x04 /* Block traversal through all symlinks
> +                                       (implies OEXT_NO_MAGICLINKS).  */
> +#endif
> +#ifndef RESOLVE_BENEATH
> +# define RESOLVE_BENEATH       0x08 /* Block "lexical" trickery like
> +                                       "..", symlinks, and absolute
> +                                       paths which escape the dirfd.  */
> +#endif
> +#ifndef RESOLVE_IN_ROOT
> +# define RESOLVE_IN_ROOT       0x10 /* Make all jumps to "/" and ".."
> +                                       be scoped inside the dirfd
> +                                       (similar to chroot).  */
> +#endif
> +#ifndef RESOLVE_CACHED
> +# define RESOLVE_CACHED                0x20 /* Only complete if resolution can be
> +                                       completed through cached lookup. May
> +                                       return -EAGAIN if that's not
> +                                       possible.  */
> +#endif
> diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
> index 96d45961e2..c81ea43dc1 100644
> --- a/sysdeps/unix/sysv/linux/csky/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
> @@ -2785,3 +2785,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
>  GLIBC_2.39 stdc_trailing_zeros_ul F
>  GLIBC_2.39 stdc_trailing_zeros_ull F
>  GLIBC_2.39 stdc_trailing_zeros_us F
> +GLIBC_2.40 openat2 F
> diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> index fbcd60c2b3..23eec25d8a 100644
> --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> @@ -2821,6 +2821,7 @@ GLIBC_2.4 sys_errlist D 0x400
>  GLIBC_2.4 sys_nerr D 0x4
>  GLIBC_2.4 unlinkat F
>  GLIBC_2.4 unshare F
> +GLIBC_2.40 openat2 F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
> index c989b433c0..4ce2afb147 100644
> --- a/sysdeps/unix/sysv/linux/i386/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
> @@ -3005,6 +3005,7 @@ GLIBC_2.4 sys_errlist D 0x210
>  GLIBC_2.4 sys_nerr D 0x4
>  GLIBC_2.4 unlinkat F
>  GLIBC_2.4 unshare F
> +GLIBC_2.40 openat2 F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
> index 0023ec1fa1..be76251b28 100644
> --- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
> @@ -2269,3 +2269,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
>  GLIBC_2.39 stdc_trailing_zeros_ul F
>  GLIBC_2.39 stdc_trailing_zeros_ull F
>  GLIBC_2.39 stdc_trailing_zeros_us F
> +GLIBC_2.40 openat2 F
> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> index d9bd6a9b56..5ff3db5035 100644
> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> @@ -2781,6 +2781,7 @@ GLIBC_2.4 xdrstdio_create F
>  GLIBC_2.4 xencrypt F
>  GLIBC_2.4 xprt_register F
>  GLIBC_2.4 xprt_unregister F
> +GLIBC_2.40 openat2 F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> index 439796d693..39645248af 100644
> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> @@ -2948,6 +2948,7 @@ GLIBC_2.4 sys_errlist D 0x210
>  GLIBC_2.4 sys_nerr D 0x4
>  GLIBC_2.4 unlinkat F
>  GLIBC_2.4 unshare F
> +GLIBC_2.40 openat2 F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> index 1069d3252c..2f917724de 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> @@ -2834,3 +2834,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
>  GLIBC_2.39 stdc_trailing_zeros_ul F
>  GLIBC_2.39 stdc_trailing_zeros_ull F
>  GLIBC_2.39 stdc_trailing_zeros_us F
> +GLIBC_2.40 openat2 F
> diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> index 17abe08c8b..6cc64f97b5 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> @@ -2831,3 +2831,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
>  GLIBC_2.39 stdc_trailing_zeros_ul F
>  GLIBC_2.39 stdc_trailing_zeros_ull F
>  GLIBC_2.39 stdc_trailing_zeros_us F
> +GLIBC_2.40 openat2 F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> index 799e508950..ae5b95bc76 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> @@ -2909,6 +2909,7 @@ GLIBC_2.4 renameat F
>  GLIBC_2.4 symlinkat F
>  GLIBC_2.4 unlinkat F
>  GLIBC_2.4 unshare F
> +GLIBC_2.40 openat2 F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> index 1c10996cbc..434e997937 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> @@ -2907,6 +2907,7 @@ GLIBC_2.4 renameat F
>  GLIBC_2.4 symlinkat F
>  GLIBC_2.4 unlinkat F
>  GLIBC_2.4 unshare F
> +GLIBC_2.40 openat2 F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> index 03d9655f26..5dc2996fcc 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> @@ -2915,6 +2915,7 @@ GLIBC_2.4 renameat F
>  GLIBC_2.4 symlinkat F
>  GLIBC_2.4 unlinkat F
>  GLIBC_2.4 unshare F
> +GLIBC_2.40 openat2 F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> index 05e402ed30..865dc5e7f1 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> @@ -2817,6 +2817,7 @@ GLIBC_2.4 renameat F
>  GLIBC_2.4 symlinkat F
>  GLIBC_2.4 unlinkat F
>  GLIBC_2.4 unshare F
> +GLIBC_2.40 openat2 F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> index 3aa81766aa..12775fdad5 100644
> --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> @@ -2873,3 +2873,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
>  GLIBC_2.39 stdc_trailing_zeros_ul F
>  GLIBC_2.39 stdc_trailing_zeros_ull F
>  GLIBC_2.39 stdc_trailing_zeros_us F
> +GLIBC_2.40 openat2 F
> diff --git a/sysdeps/unix/sysv/linux/openat2.c b/sysdeps/unix/sysv/linux/openat2.c
> new file mode 100644
> index 0000000000..a2b134bab0
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/openat2.c
> @@ -0,0 +1,29 @@
> +/* Linux openat2 syscall implementation.
> +   Copyright (C) 2024 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <fcntl.h>
> +#include <bits/openat2.h>
> +#include <sysdep-cancel.h>
> +
> +int
> +__openat2 (int dfd, const char *filename, struct open_how *how,
> +          size_t usize)
> +{
> +  return SYSCALL_CANCEL (openat2, dfd, filename, how, usize);
> +}
> +weak_alias (__openat2, openat2)
> diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist
> index c40c843aaf..2835436011 100644
> --- a/sysdeps/unix/sysv/linux/or1k/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist
> @@ -2255,3 +2255,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
>  GLIBC_2.39 stdc_trailing_zeros_ul F
>  GLIBC_2.39 stdc_trailing_zeros_ull F
>  GLIBC_2.39 stdc_trailing_zeros_us F
> +GLIBC_2.40 openat2 F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> index 9714305608..3b70a56944 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> @@ -3138,6 +3138,7 @@ GLIBC_2.4 wcstold F
>  GLIBC_2.4 wcstold_l F
>  GLIBC_2.4 wprintf F
>  GLIBC_2.4 wscanf F
> +GLIBC_2.40 openat2 F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> index 0beb52c542..677c9a75de 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> @@ -3183,6 +3183,7 @@ GLIBC_2.4 wcstold F
>  GLIBC_2.4 wcstold_l F
>  GLIBC_2.4 wprintf F
>  GLIBC_2.4 wscanf F
> +GLIBC_2.40 openat2 F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> index cfc2ebd3ec..10fc3c89dc 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> @@ -2892,6 +2892,7 @@ GLIBC_2.4 wcstold F
>  GLIBC_2.4 wcstold_l F
>  GLIBC_2.4 wprintf F
>  GLIBC_2.4 wscanf F
> +GLIBC_2.40 openat2 F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> index 8c9efc5a16..713fa1d1c8 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> @@ -2968,3 +2968,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
>  GLIBC_2.39 stdc_trailing_zeros_ul F
>  GLIBC_2.39 stdc_trailing_zeros_ull F
>  GLIBC_2.39 stdc_trailing_zeros_us F
> +GLIBC_2.40 openat2 F
> diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> index 6397a9cb91..550ba877ef 100644
> --- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> @@ -2512,3 +2512,4 @@ GLIBC_2.39 stdc_trailing_zeros_ul F
>  GLIBC_2.39 stdc_trailing_zeros_ull F
>  GLIBC_2.39 stdc_trailing_zeros_us F
>  GLIBC_2.40 __riscv_hwprobe F
> +GLIBC_2.40 openat2 F
> diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> index 71bbf94f66..8bf9f309b7 100644
> --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> @@ -2712,3 +2712,4 @@ GLIBC_2.39 stdc_trailing_zeros_ul F
>  GLIBC_2.39 stdc_trailing_zeros_ull F
>  GLIBC_2.39 stdc_trailing_zeros_us F
>  GLIBC_2.40 __riscv_hwprobe F
> +GLIBC_2.40 openat2 F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> index a7467e2850..08bc3d6f8b 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> @@ -3136,6 +3136,7 @@ GLIBC_2.4 wcstold F
>  GLIBC_2.4 wcstold_l F
>  GLIBC_2.4 wprintf F
>  GLIBC_2.4 wscanf F
> +GLIBC_2.40 openat2 F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> index fd1cb2972d..e25afff581 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> @@ -2929,6 +2929,7 @@ GLIBC_2.4 wcstold F
>  GLIBC_2.4 wcstold_l F
>  GLIBC_2.4 wprintf F
>  GLIBC_2.4 wscanf F
> +GLIBC_2.40 openat2 F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> index ff6e6b1a13..499de50ee0 100644
> --- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> @@ -2828,6 +2828,7 @@ GLIBC_2.4 sys_errlist D 0x210
>  GLIBC_2.4 sys_nerr D 0x4
>  GLIBC_2.4 unlinkat F
>  GLIBC_2.4 unshare F
> +GLIBC_2.40 openat2 F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> index 449d92bbc5..bdd9c600f0 100644
> --- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> @@ -2825,6 +2825,7 @@ GLIBC_2.4 sys_errlist D 0x210
>  GLIBC_2.4 sys_nerr D 0x4
>  GLIBC_2.4 unlinkat F
>  GLIBC_2.4 unshare F
> +GLIBC_2.40 openat2 F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> index e615be759a..b20dd43d47 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> @@ -3157,6 +3157,7 @@ GLIBC_2.4 wcstold F
>  GLIBC_2.4 wcstold_l F
>  GLIBC_2.4 wprintf F
>  GLIBC_2.4 wscanf F
> +GLIBC_2.40 openat2 F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> index bd36431dd7..19981aa981 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> @@ -2793,6 +2793,7 @@ GLIBC_2.4 sys_errlist D 0x430
>  GLIBC_2.4 sys_nerr D 0x4
>  GLIBC_2.4 unlinkat F
>  GLIBC_2.4 unshare F
> +GLIBC_2.40 openat2 F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/tst-openat2-consts.py b/sysdeps/unix/sysv/linux/tst-openat2-consts.py
> new file mode 100755
> index 0000000000..1623fafd94
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/tst-openat2-consts.py
> @@ -0,0 +1,63 @@
> +#!/usr/bin/python3
> +# Test that glibc's sys/openat2.h constants match the kernel's.
> +# Copyright (C) 2024 Free Software Foundation, Inc.
> +# This file is part of the GNU C Library.
> +#
> +# The GNU C Library is free software; you can redistribute it and/or
> +# modify it under the terms of the GNU Lesser General Public
> +# License as published by the Free Software Foundation; either
> +# version 2.1 of the License, or (at your option) any later version.
> +#
> +# The GNU C Library is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +# Lesser General Public License for more details.
> +#
> +# You should have received a copy of the GNU Lesser General Public
> +# License along with the GNU C Library; if not, see
> +# <https://www.gnu.org/licenses/>.
> +
> +import argparse
> +import sys
> +
> +import glibcextract
> +import glibcsyscalls
> +
> +
> +def main():
> +    """The main entry point."""
> +    parser = argparse.ArgumentParser(
> +        description="Test that glibc's sys/openat2.h constants "
> +        "match the kernel's.")
> +    parser.add_argument('--cc', metavar='CC',
> +                        help='C compiler (including options) to use')
> +    args = parser.parse_args()
> +
> +    if glibcextract.compile_c_snippet(
> +            '#include <linux/openat2.h>',
> +            args.cc).returncode != 0:
> +        sys.exit (77)
> +
> +    linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
> +    # Constants in glibc were updated to match Linux v6.8.  When glibc
> +    # constants are updated this value should be updated to match the
> +    # released kernel version from which the constants were taken.
> +    linux_version_glibc = (6, 8)
> +    def check(cte, exclude=None):
> +        return glibcextract.compare_macro_consts(
> +                '#define _FCNTL_H\n'
> +                '#include <stdint.h>\n'
> +                '#include <bits/openat2.h>\n',
> +                '#include <asm/fcntl.h>\n'
> +                '#include <linux/openat2.h>\n',
> +                args.cc,
> +                cte,
> +                exclude,
> +                linux_version_glibc > linux_version_headers,
> +                linux_version_headers > linux_version_glibc)
> +
> +    status = check('RESOLVE.*')
> +    sys.exit(status)
> +
> +if __name__ == '__main__':
> +    main()
> diff --git a/sysdeps/unix/sysv/linux/tst-openat2.c b/sysdeps/unix/sysv/linux/tst-openat2.c
> new file mode 100644
> index 0000000000..d0c26f2bce
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/tst-openat2.c
> @@ -0,0 +1,259 @@
> +/* Linux openat2 tests.
> +   Copyright (C) 2024 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +/* openat2 always return a file descriptor in LFS mode.  */
> +#define _FILE_OFFSET_BITS 64
> +
> +#include <array_length.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdint.h>
> +#include <support/check.h>
> +#include <support/temp_file.h>
> +#include <support/xunistd.h>
> +
> +static int dir_fd;
> +
> +static void
> +do_prepare (int argc, char *argv[])
> +{
> +  char *temp_dir = support_create_temp_directory ("tst-openat2");
> +  dir_fd = xopen (temp_dir, O_RDONLY | O_DIRECTORY, 0);
> +}
> +#define PREPARE do_prepare
> +
> +static int
> +do_test_struct (void)
> +{
> +  static struct struct_test
> +  {
> +    struct open_how_ext
> +    {
> +      struct open_how inner;
> +      int extra1;
> +      int extra2;
> +      int extra3;
> +    } arg;
> +    size_t size;
> +    int err;
> +  } tests[] =
> +  {
> +    {
> +      /* Zero size.  */
> +      .arg.inner.flags = O_RDONLY,
> +      .size = 0,
> +      .err = EINVAL,
> +    },
> +    {
> +      /* Normal struct.  */
> +      .arg.inner.flags = O_RDONLY,
> +      .size = sizeof (struct open_how),
> +    },
> +    {
> +      /* Larger struct, zeroed out the unused values.  */
> +      .arg.inner.flags = O_RDONLY,
> +      .size = sizeof (struct open_how_ext),
> +    },
> +    {
> +      /* Larger struct, non-zeroed out the unused values.  */
> +      .arg.inner.flags = O_RDONLY,
> +      .arg.extra1 = 0xdeadbeef,
> +      .size = sizeof (struct open_how_ext),
> +      .err = E2BIG,
> +    },
> +    {
> +      /* Larger struct, non-zeroed out the unused values.  */
> +      .arg.inner.flags = O_RDONLY,
> +      .arg.extra2 = 0xdeadbeef,
> +      .size = sizeof (struct open_how_ext),
> +      .err = E2BIG,
> +    },
> +  };
> +
> +  for (struct struct_test *t = tests; t != array_end (tests); t++)
> +    {
> +      int fd = openat2 (AT_FDCWD, ".", (struct open_how *) &t->arg, t->size);
> +      if (fd == -1 && errno == ENOSYS)
> +       FAIL_UNSUPPORTED ("openat2 is not supported by the kernel");
> +
> +      if (t->err != 0)
> +       {
> +         TEST_COMPARE (fd, -1);
> +         TEST_COMPARE (errno, t->err);
> +       }
> +      else
> +       TEST_VERIFY (fd >= 0);
> +    }
> +
> +  return 0;
> +}
> +
> +static int
> +do_test_flags (void)
> +{
> +  static struct flag_test
> +  {
> +    struct open_how how;
> +    int err;
> +  } tests[] =
> +  {
> +    /* O_TMPFILE is incompatible with O_PATH and O_CREAT.  */
> +    { .how.flags = O_TMPFILE | O_PATH | O_RDWR, .err = EINVAL },
> +    { .how.flags = O_TMPFILE | O_CREAT | O_RDWR, .err = EINVAL },
> +
> +    /* O_PATH only permits certain other flags to be set ...  */
> +    { .how.flags = O_PATH | O_CLOEXEC },
> +    { .how.flags = O_PATH | O_DIRECTORY },
> +    { .how.flags = O_PATH | O_NOFOLLOW },
> +    /* ... and others are absolutely not permitted. */
> +    { .how.flags = O_PATH | O_RDWR, .err = EINVAL },
> +    { .how.flags = O_PATH | O_CREAT, .err = EINVAL },
> +    { .how.flags = O_PATH | O_EXCL, .err = EINVAL },
> +    { .how.flags = O_PATH | O_NOCTTY, .err = EINVAL },
> +    { .how.flags = O_PATH | O_DIRECT, .err = EINVAL },
> +
> +    /* ->mode must only be set with O_{CREAT,TMPFILE}. */
> +    { .how.flags = O_RDONLY, .how.mode = 0600, .err = EINVAL },
> +    { .how.flags = O_PATH,   .how.mode = 0600, .err = EINVAL },
> +    { .how.flags = O_CREAT,  .how.mode = 0600 },
> +    { .how.flags = O_TMPFILE | O_RDWR, .how.mode = 0600 },
> +    /* ->mode must only contain 0777 bits. */
> +    { .how.flags = O_CREAT, .how.mode = 0xFFFF, .err = EINVAL },
> +    { .how.flags = O_CREAT, .how.mode = 0xC000000000000000ULL, .err = EINVAL },
> +    { .how.flags = O_TMPFILE | O_RDWR, .how.mode = 0x1337, .err = EINVAL },
> +    { .how.flags = O_TMPFILE | O_RDWR, .how.mode = 0x0000A00000000000ULL,
> +      .err = EINVAL },
> +
> +    /* ->resolve flags must not conflict. */
> +    { .how.flags = O_RDONLY,
> +      .how.resolve = RESOLVE_BENEATH | RESOLVE_IN_ROOT,
> +      .err = EINVAL },
> +
> +    /* ->resolve must only contain RESOLVE_* flags.  */
> +    { .how.flags = O_RDONLY,
> +      .how.resolve = 0x1337, .err = EINVAL },
> +    { .how.flags = O_CREAT,
> +      .how.resolve = 0x1337, .err = EINVAL },
> +    { .how.flags = O_TMPFILE | O_RDWR,
> +      .how.resolve = 0x1337, .err = EINVAL },
> +    { .how.flags = O_PATH,
> +      .how.resolve = 0x1337, .err = EINVAL },
> +
> +    /* currently unknown upper 32 bit rejected.  */
> +    { .how.flags = O_RDONLY | (1ULL << 63),
> +      .how.resolve = 0, .err = EINVAL },
> +  };
> +
> +  for (struct flag_test *t = tests; t != array_end (tests); t++)
> +    {
> +      char *path;
> +      if (t->how.flags & O_CREAT)
> +       {
> +         int temp_fd = create_temp_file ("tst-openat2.", &path);
> +         TEST_VERIFY_EXIT (temp_fd != -1);
> +         xunlink (path);
> +       }
> +      else
> +       path = (char *) ".";
> +
> +      int fd = openat2 (AT_FDCWD, path, &t->how, sizeof (struct open_how));
> +      if (fd != 0 && errno == EOPNOTSUPP)
> +       {
> +         /* Skip the testcase if FS does not support the operation (e.g.
> +            valid O_TMPFILE on NFS).  */
> +         continue;
> +       }
> +
> +      if (t->err != 0)
> +       {
> +         TEST_COMPARE (fd, -1);
> +         TEST_COMPARE (errno, t->err);
> +       }
> +      else
> +       TEST_VERIFY (fd >= 0);
> +    }
> +
> +  return 0;
> +}
> +
> +static int
> +do_test_basic (void)
> +{
> +  int fd;
> +
> +  fd = openat2 (dir_fd,
> +               "some-file",
> +               &(struct open_how)
> +               {
> +                 .flags = O_CREAT|O_RDWR|O_EXCL,
> +                 .mode = 0666,
> +               },
> +               sizeof (struct open_how));
> +  TEST_VERIFY (fd != -1);
> +
> +  xwrite (fd, "hello", 5);
> +
> +  /* Before closing the file, try using this file descriptor to open
> +     another file.  This must fail.  */
> +  {
> +    int fd2 = openat2 (fd,
> +                      "should-not-work",
> +                      &(struct open_how)
> +                      {
> +                        .flags = O_CREAT|O_RDWR|O_EXCL,
> +                        .mode = 0666,
> +                      },
> +                      sizeof (struct open_how));
> +    TEST_COMPARE (fd2, -1);
> +    TEST_COMPARE (errno, ENOTDIR);
> +  }
> +
> +  /* Remove the created file.  */
> +  int cwdfd = xopen (".", O_RDONLY | O_DIRECTORY, 0);
> +  TEST_COMPARE (fchdir (dir_fd), 0);
> +  xunlink ("some-file");
> +  TEST_COMPARE (fchdir (cwdfd), 0);
> +
> +  xclose (dir_fd);
> +  xclose (cwdfd);
> +
> +  fd = openat2 (dir_fd,
> +               "some-file",
> +               &(struct open_how)
> +               {
> +                 .flags = O_CREAT|O_RDWR|O_EXCL,
> +                 .mode = 0666,
> +               },
> +               sizeof (struct open_how));
> +  TEST_COMPARE (fd, -1);
> +  TEST_COMPARE (errno, EBADF);
> +
> +  return 0;
> +}
> +
> +static int
> +do_test (void)
> +{
> +  do_test_struct ();
> +  do_test_flags ();
> +  do_test_basic ();
> +
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>
> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> index aea7848ed6..a7f177c8a8 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> @@ -2744,6 +2744,7 @@ GLIBC_2.4 sys_errlist D 0x420
>  GLIBC_2.4 sys_nerr D 0x4
>  GLIBC_2.4 unlinkat F
>  GLIBC_2.4 unshare F
> +GLIBC_2.40 openat2 F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> index 4ab3681914..00dfc8f1e7 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> @@ -2763,3 +2763,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
>  GLIBC_2.39 stdc_trailing_zeros_ul F
>  GLIBC_2.39 stdc_trailing_zeros_ull F
>  GLIBC_2.39 stdc_trailing_zeros_us F
> +GLIBC_2.40 openat2 F
> --
> 2.34.1
>
Adhemerval Zanella April 24, 2024, 6:05 p.m. UTC | #2
That's a good question, since we currently do not export any kernel interface
which this new struct/size argument passing (we do use clone3, but it is
just internally). For a libc/kernel interface, it should not matter; but from
a libc exported symbol we indeed need to be more careful.

From a glibc perpectiveI think we will need to *not* include kernel UAPI header,
remove the size from the wrapper, and add some slack size on open_how for 
future extension.  It makes open_how extensions to not require new symbol
version in the near future (similar to what was done for statx). 

It would make the libc and kernel version not easily interchangeable (which 
some users do want on some cases).

On 24/04/24 14:42, enh wrote:
> doesn't glibc worry about types like this, where the size can change?
> that presents a problem for code passing those types around. do you
> require that all the code in a process be compiled with the exact same
> headers?
> 
> On Wed, Apr 24, 2024 at 10:38 AM Adhemerval Zanella
> <adhemerval.zanella@linaro.org> wrote:
>>
>> It was added on Linux 5.6, as an extension of openat.  Different than
>> other open-like functions, the kernel only provides the LFS variant (so
>> files larger than 4GB always succeed, as other functions with offset
>> larger than off_t).  Similar to other open functions, the new symbol is
>> a cancellable entrypoint.
>>
>> The test case added only stresses some of the syscalls provided
>> functionalities and it is based on an existent kernel self-test.  Since
>> the prototype does not use variadic arguments, there is no need to add a
>> fortify wrapper to catch wrong usages.
>>
>> Checked on x86_64-linux-gnu.
>> ---
>>  NEWS                                          |   4 +
>>  sysdeps/unix/sysv/linux/Makefile              |  14 +
>>  sysdeps/unix/sysv/linux/Versions              |   3 +
>>  sysdeps/unix/sysv/linux/aarch64/libc.abilist  |   1 +
>>  sysdeps/unix/sysv/linux/alpha/libc.abilist    |   1 +
>>  sysdeps/unix/sysv/linux/arc/libc.abilist      |   1 +
>>  sysdeps/unix/sysv/linux/arm/be/libc.abilist   |   1 +
>>  sysdeps/unix/sysv/linux/arm/le/libc.abilist   |   1 +
>>  sysdeps/unix/sysv/linux/bits/fcntl-linux.h    |  22 ++
>>  sysdeps/unix/sysv/linux/bits/openat2.h        |  61 +++++
>>  sysdeps/unix/sysv/linux/csky/libc.abilist     |   1 +
>>  sysdeps/unix/sysv/linux/hppa/libc.abilist     |   1 +
>>  sysdeps/unix/sysv/linux/i386/libc.abilist     |   1 +
>>  .../sysv/linux/loongarch/lp64/libc.abilist    |   1 +
>>  .../sysv/linux/m68k/coldfire/libc.abilist     |   1 +
>>  .../unix/sysv/linux/m68k/m680x0/libc.abilist  |   1 +
>>  .../sysv/linux/microblaze/be/libc.abilist     |   1 +
>>  .../sysv/linux/microblaze/le/libc.abilist     |   1 +
>>  .../sysv/linux/mips/mips32/fpu/libc.abilist   |   1 +
>>  .../sysv/linux/mips/mips32/nofpu/libc.abilist |   1 +
>>  .../sysv/linux/mips/mips64/n32/libc.abilist   |   1 +
>>  .../sysv/linux/mips/mips64/n64/libc.abilist   |   1 +
>>  sysdeps/unix/sysv/linux/nios2/libc.abilist    |   1 +
>>  sysdeps/unix/sysv/linux/openat2.c             |  29 ++
>>  sysdeps/unix/sysv/linux/or1k/libc.abilist     |   1 +
>>  .../linux/powerpc/powerpc32/fpu/libc.abilist  |   1 +
>>  .../powerpc/powerpc32/nofpu/libc.abilist      |   1 +
>>  .../linux/powerpc/powerpc64/be/libc.abilist   |   1 +
>>  .../linux/powerpc/powerpc64/le/libc.abilist   |   1 +
>>  .../unix/sysv/linux/riscv/rv32/libc.abilist   |   1 +
>>  .../unix/sysv/linux/riscv/rv64/libc.abilist   |   1 +
>>  .../unix/sysv/linux/s390/s390-32/libc.abilist |   1 +
>>  .../unix/sysv/linux/s390/s390-64/libc.abilist |   1 +
>>  sysdeps/unix/sysv/linux/sh/be/libc.abilist    |   1 +
>>  sysdeps/unix/sysv/linux/sh/le/libc.abilist    |   1 +
>>  .../sysv/linux/sparc/sparc32/libc.abilist     |   1 +
>>  .../sysv/linux/sparc/sparc64/libc.abilist     |   1 +
>>  sysdeps/unix/sysv/linux/tst-openat2-consts.py |  63 +++++
>>  sysdeps/unix/sysv/linux/tst-openat2.c         | 259 ++++++++++++++++++
>>  .../unix/sysv/linux/x86_64/64/libc.abilist    |   1 +
>>  .../unix/sysv/linux/x86_64/x32/libc.abilist   |   1 +
>>  41 files changed, 488 insertions(+)
>>  create mode 100644 sysdeps/unix/sysv/linux/bits/openat2.h
>>  create mode 100644 sysdeps/unix/sysv/linux/openat2.c
>>  create mode 100755 sysdeps/unix/sysv/linux/tst-openat2-consts.py
>>  create mode 100644 sysdeps/unix/sysv/linux/tst-openat2.c
>>
>> diff --git a/NEWS b/NEWS
>> index cf6078cf20..eaaa02cb4e 100644
>> --- a/NEWS
>> +++ b/NEWS
>> @@ -26,6 +26,10 @@ Major new features:
>>    more extensive verification tests for AT_SECURE programs and not meant to
>>    be a security feature.
>>
>> +* On Linux, the openat2 function has been added.  It is an extension of
>> +  openat and provides a superset of its functionality.  It is supported only
>> +  in LFS mode and as other open like it is a cancellable entrypoint.
>> +
>>  Deprecated and removed features, and other changes affecting compatibility:
>>
>>  * Architectures which use a 32-bit seconds-since-epoch field in struct
>> diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
>> index 415aa1f14d..4ae8ec6dc6 100644
>> --- a/sysdeps/unix/sysv/linux/Makefile
>> +++ b/sysdeps/unix/sysv/linux/Makefile
>> @@ -133,6 +133,7 @@ sysdep_headers += \
>>    bits/mman-linux.h \
>>    bits/mman-map-flags-generic.h \
>>    bits/mman-shared.h \
>> +  bits/openat2.h \
>>    bits/procfs-extra.h \
>>    bits/procfs-id.h \
>>    bits/procfs-prregset.h \
>> @@ -591,6 +592,7 @@ sysdep_routines += \
>>    internal_statvfs \
>>    open64_nocancel \
>>    open_nocancel \
>> +  openat2 \
>>    openat64_nocancel \
>>    openat_nocancel \
>>    pread64_nocancel \
>> @@ -611,7 +613,19 @@ tests += \
>>    tst-fallocate64 \
>>    tst-getcwd-smallbuff \
>>    tst-o_path-locks \
>> +  tst-openat2 \
>>    # tests
>> +
>> +tests-special += \
>> +  $(objpfx)tst-openat2-consts.out \
>> +  # tests-special
>> +$(objpfx)tst-openat2-consts.out: ../sysdeps/unix/sysv/linux/tst-openat2-consts.py
>> +       $(sysdeps-linux-python) \
>> +         ../sysdeps/unix/sysv/linux/tst-openat2-consts.py \
>> +           $(sysdeps-linux-python-cc) \
>> +         < /dev/null > $@ 2>&1; $(evaluate-test)
>> +$(objpfx)tst-openat2-consts.out: $(sysdeps-linux-python-deps)
>> +
>>  endif
>>
>>  ifeq ($(subdir),elf)
>> diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions
>> index 268ba1b6ac..65da2b617a 100644
>> --- a/sysdeps/unix/sysv/linux/Versions
>> +++ b/sysdeps/unix/sysv/linux/Versions
>> @@ -328,6 +328,9 @@ libc {
>>      posix_spawnattr_getcgroup_np;
>>      posix_spawnattr_setcgroup_np;
>>    }
>> +  GLIBC_2.40 {
>> +    openat2;
>> +  }
>>    GLIBC_PRIVATE {
>>      # functions used in other libraries
>>      __syscall_rt_sigqueueinfo;
>> diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
>> index 68eeca1c08..0b9bd8ae62 100644
>> --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
>> @@ -2748,3 +2748,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
>>  GLIBC_2.39 stdc_trailing_zeros_ul F
>>  GLIBC_2.39 stdc_trailing_zeros_ull F
>>  GLIBC_2.39 stdc_trailing_zeros_us F
>> +GLIBC_2.40 openat2 F
>> diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
>> index 34c187b721..c0bd27d617 100644
>> --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
>> @@ -3095,6 +3095,7 @@ GLIBC_2.4 wcstold F
>>  GLIBC_2.4 wcstold_l F
>>  GLIBC_2.4 wprintf F
>>  GLIBC_2.4 wscanf F
>> +GLIBC_2.40 openat2 F
>>  GLIBC_2.5 __readlinkat_chk F
>>  GLIBC_2.5 inet6_opt_append F
>>  GLIBC_2.5 inet6_opt_find F
>> diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
>> index 916c18ea94..965438e7a7 100644
>> --- a/sysdeps/unix/sysv/linux/arc/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
>> @@ -2509,3 +2509,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
>>  GLIBC_2.39 stdc_trailing_zeros_ul F
>>  GLIBC_2.39 stdc_trailing_zeros_ull F
>>  GLIBC_2.39 stdc_trailing_zeros_us F
>> +GLIBC_2.40 openat2 F
>> diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
>> index ea95de282a..e69ed8c903 100644
>> --- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
>> @@ -2801,6 +2801,7 @@ GLIBC_2.4 xdrstdio_create F
>>  GLIBC_2.4 xencrypt F
>>  GLIBC_2.4 xprt_register F
>>  GLIBC_2.4 xprt_unregister F
>> +GLIBC_2.40 openat2 F
>>  GLIBC_2.5 __readlinkat_chk F
>>  GLIBC_2.5 inet6_opt_append F
>>  GLIBC_2.5 inet6_opt_find F
>> diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
>> index 1cdbc983e1..70fd425869 100644
>> --- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
>> @@ -2798,6 +2798,7 @@ GLIBC_2.4 xdrstdio_create F
>>  GLIBC_2.4 xencrypt F
>>  GLIBC_2.4 xprt_register F
>>  GLIBC_2.4 xprt_unregister F
>> +GLIBC_2.40 openat2 F
>>  GLIBC_2.5 __readlinkat_chk F
>>  GLIBC_2.5 inet6_opt_append F
>>  GLIBC_2.5 inet6_opt_find F
>> diff --git a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
>> index 628612b885..279aa2b8eb 100644
>> --- a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
>> +++ b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
>> @@ -451,6 +451,28 @@ extern int name_to_handle_at (int __dfd, const char *__name,
>>  extern int open_by_handle_at (int __mountdirfd, struct file_handle *__handle,
>>                               int __flags);
>>
>> +#ifdef __has_include
>> +# if __has_include ("linux/openat2.h")
>> +#  include "linux/openat2.h"
>> +#  define __glibc_has_open_how 1
>> +# endif
>> +#endif
>> +
>> +#include <bits/openat2.h>
>> +
>> +/* Similar to `openat' but the arguments are packed on HOW with the size
>> +   USIZE.  If flags and mode from HOW are non-zero, then openat2 operates
>> +   like openat.
>> +
>> +   Unlike openat2, unknown or invalid flags result in an error (EINVAL),
>> +   rather than being ignored.  The mode must be zero unless one O_CREAT
>> +   or O_TMPFILE are set.
>> +
>> +   The kernel does not support legacy non-LFS interface.  */
>> +extern int openat2 (int __dfd, const char *__filename, struct open_how *__how,
>> +                   size_t __usize)
>> +     __nonnull ((2, 3));
>> +
>>  #endif /* use GNU */
>>
>>  __END_DECLS
>> diff --git a/sysdeps/unix/sysv/linux/bits/openat2.h b/sysdeps/unix/sysv/linux/bits/openat2.h
>> new file mode 100644
>> index 0000000000..a07984dace
>> --- /dev/null
>> +++ b/sysdeps/unix/sysv/linux/bits/openat2.h
>> @@ -0,0 +1,61 @@
>> +/* openat2 definition.  Linux specific.
>> +   Copyright (C) 2024 Free Software Foundation, Inc.
>> +   This file is part of the GNU C Library.
>> +
>> +   The GNU C Library is free software; you can redistribute it and/or
>> +   modify it under the terms of the GNU Lesser General Public
>> +   License as published by the Free Software Foundation; either
>> +   version 2.1 of the License, or (at your option) any later version.
>> +
>> +   The GNU C Library is distributed in the hope that it will be useful,
>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> +   Lesser General Public License for more details.
>> +
>> +   You should have received a copy of the GNU Lesser General Public
>> +   License along with the GNU C Library; if not, see
>> +   <https://www.gnu.org/licenses/>.  */
>> +
>> +#ifndef        _FCNTL_H
>> +# error "Never use <bits/openat2.h> directly; include <fcntl.h> instead."
>> +#endif
>> +
>> +#ifndef __glibc_has_open_how
>> +/* Arguments for how openat2 should open the target path.  */
>> +struct open_how
>> +{
>> +  __uint64_t flags;
>> +  __uint64_t mode;
>> +  __uint64_t resolve;
>> +};
>> +#endif
>> +
>> +/* how->resolve flags for openat2. */
>> +#ifndef RESOLVE_NO_XDEV
>> +# define RESOLVE_NO_XDEV       0x01 /* Block mount-point crossings
>> +                                       (includes bind-mounts).  */
>> +#endif
>> +#ifndef RESOLVE_NO_MAGICLINKS
>> +# define RESOLVE_NO_MAGICLINKS 0x02 /* Block traversal through procfs-style
>> +                                       "magic-links".  */
>> +#endif
>> +#ifndef RESOLVE_NO_SYMLINKS
>> +# define RESOLVE_NO_SYMLINKS   0x04 /* Block traversal through all symlinks
>> +                                       (implies OEXT_NO_MAGICLINKS).  */
>> +#endif
>> +#ifndef RESOLVE_BENEATH
>> +# define RESOLVE_BENEATH       0x08 /* Block "lexical" trickery like
>> +                                       "..", symlinks, and absolute
>> +                                       paths which escape the dirfd.  */
>> +#endif
>> +#ifndef RESOLVE_IN_ROOT
>> +# define RESOLVE_IN_ROOT       0x10 /* Make all jumps to "/" and ".."
>> +                                       be scoped inside the dirfd
>> +                                       (similar to chroot).  */
>> +#endif
>> +#ifndef RESOLVE_CACHED
>> +# define RESOLVE_CACHED                0x20 /* Only complete if resolution can be
>> +                                       completed through cached lookup. May
>> +                                       return -EAGAIN if that's not
>> +                                       possible.  */
>> +#endif
>> diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
>> index 96d45961e2..c81ea43dc1 100644
>> --- a/sysdeps/unix/sysv/linux/csky/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
>> @@ -2785,3 +2785,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
>>  GLIBC_2.39 stdc_trailing_zeros_ul F
>>  GLIBC_2.39 stdc_trailing_zeros_ull F
>>  GLIBC_2.39 stdc_trailing_zeros_us F
>> +GLIBC_2.40 openat2 F
>> diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
>> index fbcd60c2b3..23eec25d8a 100644
>> --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
>> @@ -2821,6 +2821,7 @@ GLIBC_2.4 sys_errlist D 0x400
>>  GLIBC_2.4 sys_nerr D 0x4
>>  GLIBC_2.4 unlinkat F
>>  GLIBC_2.4 unshare F
>> +GLIBC_2.40 openat2 F
>>  GLIBC_2.5 __readlinkat_chk F
>>  GLIBC_2.5 inet6_opt_append F
>>  GLIBC_2.5 inet6_opt_find F
>> diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
>> index c989b433c0..4ce2afb147 100644
>> --- a/sysdeps/unix/sysv/linux/i386/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
>> @@ -3005,6 +3005,7 @@ GLIBC_2.4 sys_errlist D 0x210
>>  GLIBC_2.4 sys_nerr D 0x4
>>  GLIBC_2.4 unlinkat F
>>  GLIBC_2.4 unshare F
>> +GLIBC_2.40 openat2 F
>>  GLIBC_2.5 __readlinkat_chk F
>>  GLIBC_2.5 inet6_opt_append F
>>  GLIBC_2.5 inet6_opt_find F
>> diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
>> index 0023ec1fa1..be76251b28 100644
>> --- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
>> @@ -2269,3 +2269,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
>>  GLIBC_2.39 stdc_trailing_zeros_ul F
>>  GLIBC_2.39 stdc_trailing_zeros_ull F
>>  GLIBC_2.39 stdc_trailing_zeros_us F
>> +GLIBC_2.40 openat2 F
>> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
>> index d9bd6a9b56..5ff3db5035 100644
>> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
>> @@ -2781,6 +2781,7 @@ GLIBC_2.4 xdrstdio_create F
>>  GLIBC_2.4 xencrypt F
>>  GLIBC_2.4 xprt_register F
>>  GLIBC_2.4 xprt_unregister F
>> +GLIBC_2.40 openat2 F
>>  GLIBC_2.5 __readlinkat_chk F
>>  GLIBC_2.5 inet6_opt_append F
>>  GLIBC_2.5 inet6_opt_find F
>> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
>> index 439796d693..39645248af 100644
>> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
>> @@ -2948,6 +2948,7 @@ GLIBC_2.4 sys_errlist D 0x210
>>  GLIBC_2.4 sys_nerr D 0x4
>>  GLIBC_2.4 unlinkat F
>>  GLIBC_2.4 unshare F
>> +GLIBC_2.40 openat2 F
>>  GLIBC_2.5 __readlinkat_chk F
>>  GLIBC_2.5 inet6_opt_append F
>>  GLIBC_2.5 inet6_opt_find F
>> diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
>> index 1069d3252c..2f917724de 100644
>> --- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
>> @@ -2834,3 +2834,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
>>  GLIBC_2.39 stdc_trailing_zeros_ul F
>>  GLIBC_2.39 stdc_trailing_zeros_ull F
>>  GLIBC_2.39 stdc_trailing_zeros_us F
>> +GLIBC_2.40 openat2 F
>> diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
>> index 17abe08c8b..6cc64f97b5 100644
>> --- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
>> @@ -2831,3 +2831,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
>>  GLIBC_2.39 stdc_trailing_zeros_ul F
>>  GLIBC_2.39 stdc_trailing_zeros_ull F
>>  GLIBC_2.39 stdc_trailing_zeros_us F
>> +GLIBC_2.40 openat2 F
>> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
>> index 799e508950..ae5b95bc76 100644
>> --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
>> @@ -2909,6 +2909,7 @@ GLIBC_2.4 renameat F
>>  GLIBC_2.4 symlinkat F
>>  GLIBC_2.4 unlinkat F
>>  GLIBC_2.4 unshare F
>> +GLIBC_2.40 openat2 F
>>  GLIBC_2.5 __readlinkat_chk F
>>  GLIBC_2.5 inet6_opt_append F
>>  GLIBC_2.5 inet6_opt_find F
>> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
>> index 1c10996cbc..434e997937 100644
>> --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
>> @@ -2907,6 +2907,7 @@ GLIBC_2.4 renameat F
>>  GLIBC_2.4 symlinkat F
>>  GLIBC_2.4 unlinkat F
>>  GLIBC_2.4 unshare F
>> +GLIBC_2.40 openat2 F
>>  GLIBC_2.5 __readlinkat_chk F
>>  GLIBC_2.5 inet6_opt_append F
>>  GLIBC_2.5 inet6_opt_find F
>> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
>> index 03d9655f26..5dc2996fcc 100644
>> --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
>> @@ -2915,6 +2915,7 @@ GLIBC_2.4 renameat F
>>  GLIBC_2.4 symlinkat F
>>  GLIBC_2.4 unlinkat F
>>  GLIBC_2.4 unshare F
>> +GLIBC_2.40 openat2 F
>>  GLIBC_2.5 __readlinkat_chk F
>>  GLIBC_2.5 inet6_opt_append F
>>  GLIBC_2.5 inet6_opt_find F
>> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
>> index 05e402ed30..865dc5e7f1 100644
>> --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
>> @@ -2817,6 +2817,7 @@ GLIBC_2.4 renameat F
>>  GLIBC_2.4 symlinkat F
>>  GLIBC_2.4 unlinkat F
>>  GLIBC_2.4 unshare F
>> +GLIBC_2.40 openat2 F
>>  GLIBC_2.5 __readlinkat_chk F
>>  GLIBC_2.5 inet6_opt_append F
>>  GLIBC_2.5 inet6_opt_find F
>> diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
>> index 3aa81766aa..12775fdad5 100644
>> --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
>> @@ -2873,3 +2873,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
>>  GLIBC_2.39 stdc_trailing_zeros_ul F
>>  GLIBC_2.39 stdc_trailing_zeros_ull F
>>  GLIBC_2.39 stdc_trailing_zeros_us F
>> +GLIBC_2.40 openat2 F
>> diff --git a/sysdeps/unix/sysv/linux/openat2.c b/sysdeps/unix/sysv/linux/openat2.c
>> new file mode 100644
>> index 0000000000..a2b134bab0
>> --- /dev/null
>> +++ b/sysdeps/unix/sysv/linux/openat2.c
>> @@ -0,0 +1,29 @@
>> +/* Linux openat2 syscall implementation.
>> +   Copyright (C) 2024 Free Software Foundation, Inc.
>> +   This file is part of the GNU C Library.
>> +
>> +   The GNU C Library is free software; you can redistribute it and/or
>> +   modify it under the terms of the GNU Lesser General Public
>> +   License as published by the Free Software Foundation; either
>> +   version 2.1 of the License, or (at your option) any later version.
>> +
>> +   The GNU C Library is distributed in the hope that it will be useful,
>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> +   Lesser General Public License for more details.
>> +
>> +   You should have received a copy of the GNU Lesser General Public
>> +   License along with the GNU C Library; if not, see
>> +   <https://www.gnu.org/licenses/>.  */
>> +
>> +#include <fcntl.h>
>> +#include <bits/openat2.h>
>> +#include <sysdep-cancel.h>
>> +
>> +int
>> +__openat2 (int dfd, const char *filename, struct open_how *how,
>> +          size_t usize)
>> +{
>> +  return SYSCALL_CANCEL (openat2, dfd, filename, how, usize);
>> +}
>> +weak_alias (__openat2, openat2)
>> diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist
>> index c40c843aaf..2835436011 100644
>> --- a/sysdeps/unix/sysv/linux/or1k/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist
>> @@ -2255,3 +2255,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
>>  GLIBC_2.39 stdc_trailing_zeros_ul F
>>  GLIBC_2.39 stdc_trailing_zeros_ull F
>>  GLIBC_2.39 stdc_trailing_zeros_us F
>> +GLIBC_2.40 openat2 F
>> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
>> index 9714305608..3b70a56944 100644
>> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
>> @@ -3138,6 +3138,7 @@ GLIBC_2.4 wcstold F
>>  GLIBC_2.4 wcstold_l F
>>  GLIBC_2.4 wprintf F
>>  GLIBC_2.4 wscanf F
>> +GLIBC_2.40 openat2 F
>>  GLIBC_2.5 __readlinkat_chk F
>>  GLIBC_2.5 inet6_opt_append F
>>  GLIBC_2.5 inet6_opt_find F
>> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
>> index 0beb52c542..677c9a75de 100644
>> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
>> @@ -3183,6 +3183,7 @@ GLIBC_2.4 wcstold F
>>  GLIBC_2.4 wcstold_l F
>>  GLIBC_2.4 wprintf F
>>  GLIBC_2.4 wscanf F
>> +GLIBC_2.40 openat2 F
>>  GLIBC_2.5 __readlinkat_chk F
>>  GLIBC_2.5 inet6_opt_append F
>>  GLIBC_2.5 inet6_opt_find F
>> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
>> index cfc2ebd3ec..10fc3c89dc 100644
>> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
>> @@ -2892,6 +2892,7 @@ GLIBC_2.4 wcstold F
>>  GLIBC_2.4 wcstold_l F
>>  GLIBC_2.4 wprintf F
>>  GLIBC_2.4 wscanf F
>> +GLIBC_2.40 openat2 F
>>  GLIBC_2.5 __readlinkat_chk F
>>  GLIBC_2.5 inet6_opt_append F
>>  GLIBC_2.5 inet6_opt_find F
>> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
>> index 8c9efc5a16..713fa1d1c8 100644
>> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
>> @@ -2968,3 +2968,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
>>  GLIBC_2.39 stdc_trailing_zeros_ul F
>>  GLIBC_2.39 stdc_trailing_zeros_ull F
>>  GLIBC_2.39 stdc_trailing_zeros_us F
>> +GLIBC_2.40 openat2 F
>> diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
>> index 6397a9cb91..550ba877ef 100644
>> --- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
>> @@ -2512,3 +2512,4 @@ GLIBC_2.39 stdc_trailing_zeros_ul F
>>  GLIBC_2.39 stdc_trailing_zeros_ull F
>>  GLIBC_2.39 stdc_trailing_zeros_us F
>>  GLIBC_2.40 __riscv_hwprobe F
>> +GLIBC_2.40 openat2 F
>> diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
>> index 71bbf94f66..8bf9f309b7 100644
>> --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
>> @@ -2712,3 +2712,4 @@ GLIBC_2.39 stdc_trailing_zeros_ul F
>>  GLIBC_2.39 stdc_trailing_zeros_ull F
>>  GLIBC_2.39 stdc_trailing_zeros_us F
>>  GLIBC_2.40 __riscv_hwprobe F
>> +GLIBC_2.40 openat2 F
>> diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
>> index a7467e2850..08bc3d6f8b 100644
>> --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
>> @@ -3136,6 +3136,7 @@ GLIBC_2.4 wcstold F
>>  GLIBC_2.4 wcstold_l F
>>  GLIBC_2.4 wprintf F
>>  GLIBC_2.4 wscanf F
>> +GLIBC_2.40 openat2 F
>>  GLIBC_2.5 __readlinkat_chk F
>>  GLIBC_2.5 inet6_opt_append F
>>  GLIBC_2.5 inet6_opt_find F
>> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
>> index fd1cb2972d..e25afff581 100644
>> --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
>> @@ -2929,6 +2929,7 @@ GLIBC_2.4 wcstold F
>>  GLIBC_2.4 wcstold_l F
>>  GLIBC_2.4 wprintf F
>>  GLIBC_2.4 wscanf F
>> +GLIBC_2.40 openat2 F
>>  GLIBC_2.5 __readlinkat_chk F
>>  GLIBC_2.5 inet6_opt_append F
>>  GLIBC_2.5 inet6_opt_find F
>> diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
>> index ff6e6b1a13..499de50ee0 100644
>> --- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
>> @@ -2828,6 +2828,7 @@ GLIBC_2.4 sys_errlist D 0x210
>>  GLIBC_2.4 sys_nerr D 0x4
>>  GLIBC_2.4 unlinkat F
>>  GLIBC_2.4 unshare F
>> +GLIBC_2.40 openat2 F
>>  GLIBC_2.5 __readlinkat_chk F
>>  GLIBC_2.5 inet6_opt_append F
>>  GLIBC_2.5 inet6_opt_find F
>> diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
>> index 449d92bbc5..bdd9c600f0 100644
>> --- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
>> @@ -2825,6 +2825,7 @@ GLIBC_2.4 sys_errlist D 0x210
>>  GLIBC_2.4 sys_nerr D 0x4
>>  GLIBC_2.4 unlinkat F
>>  GLIBC_2.4 unshare F
>> +GLIBC_2.40 openat2 F
>>  GLIBC_2.5 __readlinkat_chk F
>>  GLIBC_2.5 inet6_opt_append F
>>  GLIBC_2.5 inet6_opt_find F
>> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
>> index e615be759a..b20dd43d47 100644
>> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
>> @@ -3157,6 +3157,7 @@ GLIBC_2.4 wcstold F
>>  GLIBC_2.4 wcstold_l F
>>  GLIBC_2.4 wprintf F
>>  GLIBC_2.4 wscanf F
>> +GLIBC_2.40 openat2 F
>>  GLIBC_2.5 __readlinkat_chk F
>>  GLIBC_2.5 inet6_opt_append F
>>  GLIBC_2.5 inet6_opt_find F
>> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
>> index bd36431dd7..19981aa981 100644
>> --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
>> @@ -2793,6 +2793,7 @@ GLIBC_2.4 sys_errlist D 0x430
>>  GLIBC_2.4 sys_nerr D 0x4
>>  GLIBC_2.4 unlinkat F
>>  GLIBC_2.4 unshare F
>> +GLIBC_2.40 openat2 F
>>  GLIBC_2.5 __readlinkat_chk F
>>  GLIBC_2.5 inet6_opt_append F
>>  GLIBC_2.5 inet6_opt_find F
>> diff --git a/sysdeps/unix/sysv/linux/tst-openat2-consts.py b/sysdeps/unix/sysv/linux/tst-openat2-consts.py
>> new file mode 100755
>> index 0000000000..1623fafd94
>> --- /dev/null
>> +++ b/sysdeps/unix/sysv/linux/tst-openat2-consts.py
>> @@ -0,0 +1,63 @@
>> +#!/usr/bin/python3
>> +# Test that glibc's sys/openat2.h constants match the kernel's.
>> +# Copyright (C) 2024 Free Software Foundation, Inc.
>> +# This file is part of the GNU C Library.
>> +#
>> +# The GNU C Library is free software; you can redistribute it and/or
>> +# modify it under the terms of the GNU Lesser General Public
>> +# License as published by the Free Software Foundation; either
>> +# version 2.1 of the License, or (at your option) any later version.
>> +#
>> +# The GNU C Library is distributed in the hope that it will be useful,
>> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> +# Lesser General Public License for more details.
>> +#
>> +# You should have received a copy of the GNU Lesser General Public
>> +# License along with the GNU C Library; if not, see
>> +# <https://www.gnu.org/licenses/>.
>> +
>> +import argparse
>> +import sys
>> +
>> +import glibcextract
>> +import glibcsyscalls
>> +
>> +
>> +def main():
>> +    """The main entry point."""
>> +    parser = argparse.ArgumentParser(
>> +        description="Test that glibc's sys/openat2.h constants "
>> +        "match the kernel's.")
>> +    parser.add_argument('--cc', metavar='CC',
>> +                        help='C compiler (including options) to use')
>> +    args = parser.parse_args()
>> +
>> +    if glibcextract.compile_c_snippet(
>> +            '#include <linux/openat2.h>',
>> +            args.cc).returncode != 0:
>> +        sys.exit (77)
>> +
>> +    linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
>> +    # Constants in glibc were updated to match Linux v6.8.  When glibc
>> +    # constants are updated this value should be updated to match the
>> +    # released kernel version from which the constants were taken.
>> +    linux_version_glibc = (6, 8)
>> +    def check(cte, exclude=None):
>> +        return glibcextract.compare_macro_consts(
>> +                '#define _FCNTL_H\n'
>> +                '#include <stdint.h>\n'
>> +                '#include <bits/openat2.h>\n',
>> +                '#include <asm/fcntl.h>\n'
>> +                '#include <linux/openat2.h>\n',
>> +                args.cc,
>> +                cte,
>> +                exclude,
>> +                linux_version_glibc > linux_version_headers,
>> +                linux_version_headers > linux_version_glibc)
>> +
>> +    status = check('RESOLVE.*')
>> +    sys.exit(status)
>> +
>> +if __name__ == '__main__':
>> +    main()
>> diff --git a/sysdeps/unix/sysv/linux/tst-openat2.c b/sysdeps/unix/sysv/linux/tst-openat2.c
>> new file mode 100644
>> index 0000000000..d0c26f2bce
>> --- /dev/null
>> +++ b/sysdeps/unix/sysv/linux/tst-openat2.c
>> @@ -0,0 +1,259 @@
>> +/* Linux openat2 tests.
>> +   Copyright (C) 2024 Free Software Foundation, Inc.
>> +   This file is part of the GNU C Library.
>> +
>> +   The GNU C Library is free software; you can redistribute it and/or
>> +   modify it under the terms of the GNU Lesser General Public
>> +   License as published by the Free Software Foundation; either
>> +   version 2.1 of the License, or (at your option) any later version.
>> +
>> +   The GNU C Library is distributed in the hope that it will be useful,
>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> +   Lesser General Public License for more details.
>> +
>> +   You should have received a copy of the GNU Lesser General Public
>> +   License along with the GNU C Library; if not, see
>> +   <https://www.gnu.org/licenses/>.  */
>> +
>> +/* openat2 always return a file descriptor in LFS mode.  */
>> +#define _FILE_OFFSET_BITS 64
>> +
>> +#include <array_length.h>
>> +#include <errno.h>
>> +#include <fcntl.h>
>> +#include <stdint.h>
>> +#include <support/check.h>
>> +#include <support/temp_file.h>
>> +#include <support/xunistd.h>
>> +
>> +static int dir_fd;
>> +
>> +static void
>> +do_prepare (int argc, char *argv[])
>> +{
>> +  char *temp_dir = support_create_temp_directory ("tst-openat2");
>> +  dir_fd = xopen (temp_dir, O_RDONLY | O_DIRECTORY, 0);
>> +}
>> +#define PREPARE do_prepare
>> +
>> +static int
>> +do_test_struct (void)
>> +{
>> +  static struct struct_test
>> +  {
>> +    struct open_how_ext
>> +    {
>> +      struct open_how inner;
>> +      int extra1;
>> +      int extra2;
>> +      int extra3;
>> +    } arg;
>> +    size_t size;
>> +    int err;
>> +  } tests[] =
>> +  {
>> +    {
>> +      /* Zero size.  */
>> +      .arg.inner.flags = O_RDONLY,
>> +      .size = 0,
>> +      .err = EINVAL,
>> +    },
>> +    {
>> +      /* Normal struct.  */
>> +      .arg.inner.flags = O_RDONLY,
>> +      .size = sizeof (struct open_how),
>> +    },
>> +    {
>> +      /* Larger struct, zeroed out the unused values.  */
>> +      .arg.inner.flags = O_RDONLY,
>> +      .size = sizeof (struct open_how_ext),
>> +    },
>> +    {
>> +      /* Larger struct, non-zeroed out the unused values.  */
>> +      .arg.inner.flags = O_RDONLY,
>> +      .arg.extra1 = 0xdeadbeef,
>> +      .size = sizeof (struct open_how_ext),
>> +      .err = E2BIG,
>> +    },
>> +    {
>> +      /* Larger struct, non-zeroed out the unused values.  */
>> +      .arg.inner.flags = O_RDONLY,
>> +      .arg.extra2 = 0xdeadbeef,
>> +      .size = sizeof (struct open_how_ext),
>> +      .err = E2BIG,
>> +    },
>> +  };
>> +
>> +  for (struct struct_test *t = tests; t != array_end (tests); t++)
>> +    {
>> +      int fd = openat2 (AT_FDCWD, ".", (struct open_how *) &t->arg, t->size);
>> +      if (fd == -1 && errno == ENOSYS)
>> +       FAIL_UNSUPPORTED ("openat2 is not supported by the kernel");
>> +
>> +      if (t->err != 0)
>> +       {
>> +         TEST_COMPARE (fd, -1);
>> +         TEST_COMPARE (errno, t->err);
>> +       }
>> +      else
>> +       TEST_VERIFY (fd >= 0);
>> +    }
>> +
>> +  return 0;
>> +}
>> +
>> +static int
>> +do_test_flags (void)
>> +{
>> +  static struct flag_test
>> +  {
>> +    struct open_how how;
>> +    int err;
>> +  } tests[] =
>> +  {
>> +    /* O_TMPFILE is incompatible with O_PATH and O_CREAT.  */
>> +    { .how.flags = O_TMPFILE | O_PATH | O_RDWR, .err = EINVAL },
>> +    { .how.flags = O_TMPFILE | O_CREAT | O_RDWR, .err = EINVAL },
>> +
>> +    /* O_PATH only permits certain other flags to be set ...  */
>> +    { .how.flags = O_PATH | O_CLOEXEC },
>> +    { .how.flags = O_PATH | O_DIRECTORY },
>> +    { .how.flags = O_PATH | O_NOFOLLOW },
>> +    /* ... and others are absolutely not permitted. */
>> +    { .how.flags = O_PATH | O_RDWR, .err = EINVAL },
>> +    { .how.flags = O_PATH | O_CREAT, .err = EINVAL },
>> +    { .how.flags = O_PATH | O_EXCL, .err = EINVAL },
>> +    { .how.flags = O_PATH | O_NOCTTY, .err = EINVAL },
>> +    { .how.flags = O_PATH | O_DIRECT, .err = EINVAL },
>> +
>> +    /* ->mode must only be set with O_{CREAT,TMPFILE}. */
>> +    { .how.flags = O_RDONLY, .how.mode = 0600, .err = EINVAL },
>> +    { .how.flags = O_PATH,   .how.mode = 0600, .err = EINVAL },
>> +    { .how.flags = O_CREAT,  .how.mode = 0600 },
>> +    { .how.flags = O_TMPFILE | O_RDWR, .how.mode = 0600 },
>> +    /* ->mode must only contain 0777 bits. */
>> +    { .how.flags = O_CREAT, .how.mode = 0xFFFF, .err = EINVAL },
>> +    { .how.flags = O_CREAT, .how.mode = 0xC000000000000000ULL, .err = EINVAL },
>> +    { .how.flags = O_TMPFILE | O_RDWR, .how.mode = 0x1337, .err = EINVAL },
>> +    { .how.flags = O_TMPFILE | O_RDWR, .how.mode = 0x0000A00000000000ULL,
>> +      .err = EINVAL },
>> +
>> +    /* ->resolve flags must not conflict. */
>> +    { .how.flags = O_RDONLY,
>> +      .how.resolve = RESOLVE_BENEATH | RESOLVE_IN_ROOT,
>> +      .err = EINVAL },
>> +
>> +    /* ->resolve must only contain RESOLVE_* flags.  */
>> +    { .how.flags = O_RDONLY,
>> +      .how.resolve = 0x1337, .err = EINVAL },
>> +    { .how.flags = O_CREAT,
>> +      .how.resolve = 0x1337, .err = EINVAL },
>> +    { .how.flags = O_TMPFILE | O_RDWR,
>> +      .how.resolve = 0x1337, .err = EINVAL },
>> +    { .how.flags = O_PATH,
>> +      .how.resolve = 0x1337, .err = EINVAL },
>> +
>> +    /* currently unknown upper 32 bit rejected.  */
>> +    { .how.flags = O_RDONLY | (1ULL << 63),
>> +      .how.resolve = 0, .err = EINVAL },
>> +  };
>> +
>> +  for (struct flag_test *t = tests; t != array_end (tests); t++)
>> +    {
>> +      char *path;
>> +      if (t->how.flags & O_CREAT)
>> +       {
>> +         int temp_fd = create_temp_file ("tst-openat2.", &path);
>> +         TEST_VERIFY_EXIT (temp_fd != -1);
>> +         xunlink (path);
>> +       }
>> +      else
>> +       path = (char *) ".";
>> +
>> +      int fd = openat2 (AT_FDCWD, path, &t->how, sizeof (struct open_how));
>> +      if (fd != 0 && errno == EOPNOTSUPP)
>> +       {
>> +         /* Skip the testcase if FS does not support the operation (e.g.
>> +            valid O_TMPFILE on NFS).  */
>> +         continue;
>> +       }
>> +
>> +      if (t->err != 0)
>> +       {
>> +         TEST_COMPARE (fd, -1);
>> +         TEST_COMPARE (errno, t->err);
>> +       }
>> +      else
>> +       TEST_VERIFY (fd >= 0);
>> +    }
>> +
>> +  return 0;
>> +}
>> +
>> +static int
>> +do_test_basic (void)
>> +{
>> +  int fd;
>> +
>> +  fd = openat2 (dir_fd,
>> +               "some-file",
>> +               &(struct open_how)
>> +               {
>> +                 .flags = O_CREAT|O_RDWR|O_EXCL,
>> +                 .mode = 0666,
>> +               },
>> +               sizeof (struct open_how));
>> +  TEST_VERIFY (fd != -1);
>> +
>> +  xwrite (fd, "hello", 5);
>> +
>> +  /* Before closing the file, try using this file descriptor to open
>> +     another file.  This must fail.  */
>> +  {
>> +    int fd2 = openat2 (fd,
>> +                      "should-not-work",
>> +                      &(struct open_how)
>> +                      {
>> +                        .flags = O_CREAT|O_RDWR|O_EXCL,
>> +                        .mode = 0666,
>> +                      },
>> +                      sizeof (struct open_how));
>> +    TEST_COMPARE (fd2, -1);
>> +    TEST_COMPARE (errno, ENOTDIR);
>> +  }
>> +
>> +  /* Remove the created file.  */
>> +  int cwdfd = xopen (".", O_RDONLY | O_DIRECTORY, 0);
>> +  TEST_COMPARE (fchdir (dir_fd), 0);
>> +  xunlink ("some-file");
>> +  TEST_COMPARE (fchdir (cwdfd), 0);
>> +
>> +  xclose (dir_fd);
>> +  xclose (cwdfd);
>> +
>> +  fd = openat2 (dir_fd,
>> +               "some-file",
>> +               &(struct open_how)
>> +               {
>> +                 .flags = O_CREAT|O_RDWR|O_EXCL,
>> +                 .mode = 0666,
>> +               },
>> +               sizeof (struct open_how));
>> +  TEST_COMPARE (fd, -1);
>> +  TEST_COMPARE (errno, EBADF);
>> +
>> +  return 0;
>> +}
>> +
>> +static int
>> +do_test (void)
>> +{
>> +  do_test_struct ();
>> +  do_test_flags ();
>> +  do_test_basic ();
>> +
>> +  return 0;
>> +}
>> +
>> +#include <support/test-driver.c>
>> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
>> index aea7848ed6..a7f177c8a8 100644
>> --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
>> @@ -2744,6 +2744,7 @@ GLIBC_2.4 sys_errlist D 0x420
>>  GLIBC_2.4 sys_nerr D 0x4
>>  GLIBC_2.4 unlinkat F
>>  GLIBC_2.4 unshare F
>> +GLIBC_2.40 openat2 F
>>  GLIBC_2.5 __readlinkat_chk F
>>  GLIBC_2.5 inet6_opt_append F
>>  GLIBC_2.5 inet6_opt_find F
>> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
>> index 4ab3681914..00dfc8f1e7 100644
>> --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
>> @@ -2763,3 +2763,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
>>  GLIBC_2.39 stdc_trailing_zeros_ul F
>>  GLIBC_2.39 stdc_trailing_zeros_ull F
>>  GLIBC_2.39 stdc_trailing_zeros_us F
>> +GLIBC_2.40 openat2 F
>> --
>> 2.34.1
>>
enh April 24, 2024, 9:18 p.m. UTC | #3
On Wed, Apr 24, 2024 at 11:05 AM Adhemerval Zanella Netto
<adhemerval.zanella@linaro.org> wrote:
>
> That's a good question, since we currently do not export any kernel interface
> which this new struct/size argument passing (we do use clone3, but it is
> just internally). For a libc/kernel interface, it should not matter; but from
> a libc exported symbol we indeed need to be more careful.
>
> From a glibc perpectiveI think we will need to *not* include kernel UAPI header,
> remove the size from the wrapper, and add some slack size on open_how for
> future extension.  It makes open_how extensions to not require new symbol
> version in the near future (similar to what was done for statx).

i think statx did that _in uapi_, no? there's already padding
upstream. (that's a much better way to do these things from a libc
perspective; if someone talks to the kernel folks, it's worth trying
to encourage them to do more of that, and less of the openat2() or
sched_setattr().)

> It would make the libc and kernel version not easily interchangeable (which
> some users do want on some cases).
>
> On 24/04/24 14:42, enh wrote:
> > doesn't glibc worry about types like this, where the size can change?
> > that presents a problem for code passing those types around. do you
> > require that all the code in a process be compiled with the exact same
> > headers?
> >
> > On Wed, Apr 24, 2024 at 10:38 AM Adhemerval Zanella
> > <adhemerval.zanella@linaro.org> wrote:
> >>
> >> It was added on Linux 5.6, as an extension of openat.  Different than
> >> other open-like functions, the kernel only provides the LFS variant (so
> >> files larger than 4GB always succeed, as other functions with offset
> >> larger than off_t).  Similar to other open functions, the new symbol is
> >> a cancellable entrypoint.
> >>
> >> The test case added only stresses some of the syscalls provided
> >> functionalities and it is based on an existent kernel self-test.  Since
> >> the prototype does not use variadic arguments, there is no need to add a
> >> fortify wrapper to catch wrong usages.
> >>
> >> Checked on x86_64-linux-gnu.
> >> ---
> >>  NEWS                                          |   4 +
> >>  sysdeps/unix/sysv/linux/Makefile              |  14 +
> >>  sysdeps/unix/sysv/linux/Versions              |   3 +
> >>  sysdeps/unix/sysv/linux/aarch64/libc.abilist  |   1 +
> >>  sysdeps/unix/sysv/linux/alpha/libc.abilist    |   1 +
> >>  sysdeps/unix/sysv/linux/arc/libc.abilist      |   1 +
> >>  sysdeps/unix/sysv/linux/arm/be/libc.abilist   |   1 +
> >>  sysdeps/unix/sysv/linux/arm/le/libc.abilist   |   1 +
> >>  sysdeps/unix/sysv/linux/bits/fcntl-linux.h    |  22 ++
> >>  sysdeps/unix/sysv/linux/bits/openat2.h        |  61 +++++
> >>  sysdeps/unix/sysv/linux/csky/libc.abilist     |   1 +
> >>  sysdeps/unix/sysv/linux/hppa/libc.abilist     |   1 +
> >>  sysdeps/unix/sysv/linux/i386/libc.abilist     |   1 +
> >>  .../sysv/linux/loongarch/lp64/libc.abilist    |   1 +
> >>  .../sysv/linux/m68k/coldfire/libc.abilist     |   1 +
> >>  .../unix/sysv/linux/m68k/m680x0/libc.abilist  |   1 +
> >>  .../sysv/linux/microblaze/be/libc.abilist     |   1 +
> >>  .../sysv/linux/microblaze/le/libc.abilist     |   1 +
> >>  .../sysv/linux/mips/mips32/fpu/libc.abilist   |   1 +
> >>  .../sysv/linux/mips/mips32/nofpu/libc.abilist |   1 +
> >>  .../sysv/linux/mips/mips64/n32/libc.abilist   |   1 +
> >>  .../sysv/linux/mips/mips64/n64/libc.abilist   |   1 +
> >>  sysdeps/unix/sysv/linux/nios2/libc.abilist    |   1 +
> >>  sysdeps/unix/sysv/linux/openat2.c             |  29 ++
> >>  sysdeps/unix/sysv/linux/or1k/libc.abilist     |   1 +
> >>  .../linux/powerpc/powerpc32/fpu/libc.abilist  |   1 +
> >>  .../powerpc/powerpc32/nofpu/libc.abilist      |   1 +
> >>  .../linux/powerpc/powerpc64/be/libc.abilist   |   1 +
> >>  .../linux/powerpc/powerpc64/le/libc.abilist   |   1 +
> >>  .../unix/sysv/linux/riscv/rv32/libc.abilist   |   1 +
> >>  .../unix/sysv/linux/riscv/rv64/libc.abilist   |   1 +
> >>  .../unix/sysv/linux/s390/s390-32/libc.abilist |   1 +
> >>  .../unix/sysv/linux/s390/s390-64/libc.abilist |   1 +
> >>  sysdeps/unix/sysv/linux/sh/be/libc.abilist    |   1 +
> >>  sysdeps/unix/sysv/linux/sh/le/libc.abilist    |   1 +
> >>  .../sysv/linux/sparc/sparc32/libc.abilist     |   1 +
> >>  .../sysv/linux/sparc/sparc64/libc.abilist     |   1 +
> >>  sysdeps/unix/sysv/linux/tst-openat2-consts.py |  63 +++++
> >>  sysdeps/unix/sysv/linux/tst-openat2.c         | 259 ++++++++++++++++++
> >>  .../unix/sysv/linux/x86_64/64/libc.abilist    |   1 +
> >>  .../unix/sysv/linux/x86_64/x32/libc.abilist   |   1 +
> >>  41 files changed, 488 insertions(+)
> >>  create mode 100644 sysdeps/unix/sysv/linux/bits/openat2.h
> >>  create mode 100644 sysdeps/unix/sysv/linux/openat2.c
> >>  create mode 100755 sysdeps/unix/sysv/linux/tst-openat2-consts.py
> >>  create mode 100644 sysdeps/unix/sysv/linux/tst-openat2.c
> >>
> >> diff --git a/NEWS b/NEWS
> >> index cf6078cf20..eaaa02cb4e 100644
> >> --- a/NEWS
> >> +++ b/NEWS
> >> @@ -26,6 +26,10 @@ Major new features:
> >>    more extensive verification tests for AT_SECURE programs and not meant to
> >>    be a security feature.
> >>
> >> +* On Linux, the openat2 function has been added.  It is an extension of
> >> +  openat and provides a superset of its functionality.  It is supported only
> >> +  in LFS mode and as other open like it is a cancellable entrypoint.
> >> +
> >>  Deprecated and removed features, and other changes affecting compatibility:
> >>
> >>  * Architectures which use a 32-bit seconds-since-epoch field in struct
> >> diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
> >> index 415aa1f14d..4ae8ec6dc6 100644
> >> --- a/sysdeps/unix/sysv/linux/Makefile
> >> +++ b/sysdeps/unix/sysv/linux/Makefile
> >> @@ -133,6 +133,7 @@ sysdep_headers += \
> >>    bits/mman-linux.h \
> >>    bits/mman-map-flags-generic.h \
> >>    bits/mman-shared.h \
> >> +  bits/openat2.h \
> >>    bits/procfs-extra.h \
> >>    bits/procfs-id.h \
> >>    bits/procfs-prregset.h \
> >> @@ -591,6 +592,7 @@ sysdep_routines += \
> >>    internal_statvfs \
> >>    open64_nocancel \
> >>    open_nocancel \
> >> +  openat2 \
> >>    openat64_nocancel \
> >>    openat_nocancel \
> >>    pread64_nocancel \
> >> @@ -611,7 +613,19 @@ tests += \
> >>    tst-fallocate64 \
> >>    tst-getcwd-smallbuff \
> >>    tst-o_path-locks \
> >> +  tst-openat2 \
> >>    # tests
> >> +
> >> +tests-special += \
> >> +  $(objpfx)tst-openat2-consts.out \
> >> +  # tests-special
> >> +$(objpfx)tst-openat2-consts.out: ../sysdeps/unix/sysv/linux/tst-openat2-consts.py
> >> +       $(sysdeps-linux-python) \
> >> +         ../sysdeps/unix/sysv/linux/tst-openat2-consts.py \
> >> +           $(sysdeps-linux-python-cc) \
> >> +         < /dev/null > $@ 2>&1; $(evaluate-test)
> >> +$(objpfx)tst-openat2-consts.out: $(sysdeps-linux-python-deps)
> >> +
> >>  endif
> >>
> >>  ifeq ($(subdir),elf)
> >> diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions
> >> index 268ba1b6ac..65da2b617a 100644
> >> --- a/sysdeps/unix/sysv/linux/Versions
> >> +++ b/sysdeps/unix/sysv/linux/Versions
> >> @@ -328,6 +328,9 @@ libc {
> >>      posix_spawnattr_getcgroup_np;
> >>      posix_spawnattr_setcgroup_np;
> >>    }
> >> +  GLIBC_2.40 {
> >> +    openat2;
> >> +  }
> >>    GLIBC_PRIVATE {
> >>      # functions used in other libraries
> >>      __syscall_rt_sigqueueinfo;
> >> diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> >> index 68eeca1c08..0b9bd8ae62 100644
> >> --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> >> @@ -2748,3 +2748,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
> >>  GLIBC_2.39 stdc_trailing_zeros_ul F
> >>  GLIBC_2.39 stdc_trailing_zeros_ull F
> >>  GLIBC_2.39 stdc_trailing_zeros_us F
> >> +GLIBC_2.40 openat2 F
> >> diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> >> index 34c187b721..c0bd27d617 100644
> >> --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> >> @@ -3095,6 +3095,7 @@ GLIBC_2.4 wcstold F
> >>  GLIBC_2.4 wcstold_l F
> >>  GLIBC_2.4 wprintf F
> >>  GLIBC_2.4 wscanf F
> >> +GLIBC_2.40 openat2 F
> >>  GLIBC_2.5 __readlinkat_chk F
> >>  GLIBC_2.5 inet6_opt_append F
> >>  GLIBC_2.5 inet6_opt_find F
> >> diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
> >> index 916c18ea94..965438e7a7 100644
> >> --- a/sysdeps/unix/sysv/linux/arc/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
> >> @@ -2509,3 +2509,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
> >>  GLIBC_2.39 stdc_trailing_zeros_ul F
> >>  GLIBC_2.39 stdc_trailing_zeros_ull F
> >>  GLIBC_2.39 stdc_trailing_zeros_us F
> >> +GLIBC_2.40 openat2 F
> >> diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> >> index ea95de282a..e69ed8c903 100644
> >> --- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> >> @@ -2801,6 +2801,7 @@ GLIBC_2.4 xdrstdio_create F
> >>  GLIBC_2.4 xencrypt F
> >>  GLIBC_2.4 xprt_register F
> >>  GLIBC_2.4 xprt_unregister F
> >> +GLIBC_2.40 openat2 F
> >>  GLIBC_2.5 __readlinkat_chk F
> >>  GLIBC_2.5 inet6_opt_append F
> >>  GLIBC_2.5 inet6_opt_find F
> >> diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> >> index 1cdbc983e1..70fd425869 100644
> >> --- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> >> @@ -2798,6 +2798,7 @@ GLIBC_2.4 xdrstdio_create F
> >>  GLIBC_2.4 xencrypt F
> >>  GLIBC_2.4 xprt_register F
> >>  GLIBC_2.4 xprt_unregister F
> >> +GLIBC_2.40 openat2 F
> >>  GLIBC_2.5 __readlinkat_chk F
> >>  GLIBC_2.5 inet6_opt_append F
> >>  GLIBC_2.5 inet6_opt_find F
> >> diff --git a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
> >> index 628612b885..279aa2b8eb 100644
> >> --- a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
> >> +++ b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
> >> @@ -451,6 +451,28 @@ extern int name_to_handle_at (int __dfd, const char *__name,
> >>  extern int open_by_handle_at (int __mountdirfd, struct file_handle *__handle,
> >>                               int __flags);
> >>
> >> +#ifdef __has_include
> >> +# if __has_include ("linux/openat2.h")
> >> +#  include "linux/openat2.h"
> >> +#  define __glibc_has_open_how 1
> >> +# endif
> >> +#endif
> >> +
> >> +#include <bits/openat2.h>
> >> +
> >> +/* Similar to `openat' but the arguments are packed on HOW with the size
> >> +   USIZE.  If flags and mode from HOW are non-zero, then openat2 operates
> >> +   like openat.
> >> +
> >> +   Unlike openat2, unknown or invalid flags result in an error (EINVAL),
> >> +   rather than being ignored.  The mode must be zero unless one O_CREAT
> >> +   or O_TMPFILE are set.
> >> +
> >> +   The kernel does not support legacy non-LFS interface.  */
> >> +extern int openat2 (int __dfd, const char *__filename, struct open_how *__how,
> >> +                   size_t __usize)
> >> +     __nonnull ((2, 3));
> >> +
> >>  #endif /* use GNU */
> >>
> >>  __END_DECLS
> >> diff --git a/sysdeps/unix/sysv/linux/bits/openat2.h b/sysdeps/unix/sysv/linux/bits/openat2.h
> >> new file mode 100644
> >> index 0000000000..a07984dace
> >> --- /dev/null
> >> +++ b/sysdeps/unix/sysv/linux/bits/openat2.h
> >> @@ -0,0 +1,61 @@
> >> +/* openat2 definition.  Linux specific.
> >> +   Copyright (C) 2024 Free Software Foundation, Inc.
> >> +   This file is part of the GNU C Library.
> >> +
> >> +   The GNU C Library is free software; you can redistribute it and/or
> >> +   modify it under the terms of the GNU Lesser General Public
> >> +   License as published by the Free Software Foundation; either
> >> +   version 2.1 of the License, or (at your option) any later version.
> >> +
> >> +   The GNU C Library is distributed in the hope that it will be useful,
> >> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> >> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> >> +   Lesser General Public License for more details.
> >> +
> >> +   You should have received a copy of the GNU Lesser General Public
> >> +   License along with the GNU C Library; if not, see
> >> +   <https://www.gnu.org/licenses/>.  */
> >> +
> >> +#ifndef        _FCNTL_H
> >> +# error "Never use <bits/openat2.h> directly; include <fcntl.h> instead."
> >> +#endif
> >> +
> >> +#ifndef __glibc_has_open_how
> >> +/* Arguments for how openat2 should open the target path.  */
> >> +struct open_how
> >> +{
> >> +  __uint64_t flags;
> >> +  __uint64_t mode;
> >> +  __uint64_t resolve;
> >> +};
> >> +#endif
> >> +
> >> +/* how->resolve flags for openat2. */
> >> +#ifndef RESOLVE_NO_XDEV
> >> +# define RESOLVE_NO_XDEV       0x01 /* Block mount-point crossings
> >> +                                       (includes bind-mounts).  */
> >> +#endif
> >> +#ifndef RESOLVE_NO_MAGICLINKS
> >> +# define RESOLVE_NO_MAGICLINKS 0x02 /* Block traversal through procfs-style
> >> +                                       "magic-links".  */
> >> +#endif
> >> +#ifndef RESOLVE_NO_SYMLINKS
> >> +# define RESOLVE_NO_SYMLINKS   0x04 /* Block traversal through all symlinks
> >> +                                       (implies OEXT_NO_MAGICLINKS).  */
> >> +#endif
> >> +#ifndef RESOLVE_BENEATH
> >> +# define RESOLVE_BENEATH       0x08 /* Block "lexical" trickery like
> >> +                                       "..", symlinks, and absolute
> >> +                                       paths which escape the dirfd.  */
> >> +#endif
> >> +#ifndef RESOLVE_IN_ROOT
> >> +# define RESOLVE_IN_ROOT       0x10 /* Make all jumps to "/" and ".."
> >> +                                       be scoped inside the dirfd
> >> +                                       (similar to chroot).  */
> >> +#endif
> >> +#ifndef RESOLVE_CACHED
> >> +# define RESOLVE_CACHED                0x20 /* Only complete if resolution can be
> >> +                                       completed through cached lookup. May
> >> +                                       return -EAGAIN if that's not
> >> +                                       possible.  */
> >> +#endif
> >> diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
> >> index 96d45961e2..c81ea43dc1 100644
> >> --- a/sysdeps/unix/sysv/linux/csky/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
> >> @@ -2785,3 +2785,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
> >>  GLIBC_2.39 stdc_trailing_zeros_ul F
> >>  GLIBC_2.39 stdc_trailing_zeros_ull F
> >>  GLIBC_2.39 stdc_trailing_zeros_us F
> >> +GLIBC_2.40 openat2 F
> >> diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> >> index fbcd60c2b3..23eec25d8a 100644
> >> --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> >> @@ -2821,6 +2821,7 @@ GLIBC_2.4 sys_errlist D 0x400
> >>  GLIBC_2.4 sys_nerr D 0x4
> >>  GLIBC_2.4 unlinkat F
> >>  GLIBC_2.4 unshare F
> >> +GLIBC_2.40 openat2 F
> >>  GLIBC_2.5 __readlinkat_chk F
> >>  GLIBC_2.5 inet6_opt_append F
> >>  GLIBC_2.5 inet6_opt_find F
> >> diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
> >> index c989b433c0..4ce2afb147 100644
> >> --- a/sysdeps/unix/sysv/linux/i386/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
> >> @@ -3005,6 +3005,7 @@ GLIBC_2.4 sys_errlist D 0x210
> >>  GLIBC_2.4 sys_nerr D 0x4
> >>  GLIBC_2.4 unlinkat F
> >>  GLIBC_2.4 unshare F
> >> +GLIBC_2.40 openat2 F
> >>  GLIBC_2.5 __readlinkat_chk F
> >>  GLIBC_2.5 inet6_opt_append F
> >>  GLIBC_2.5 inet6_opt_find F
> >> diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
> >> index 0023ec1fa1..be76251b28 100644
> >> --- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
> >> @@ -2269,3 +2269,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
> >>  GLIBC_2.39 stdc_trailing_zeros_ul F
> >>  GLIBC_2.39 stdc_trailing_zeros_ull F
> >>  GLIBC_2.39 stdc_trailing_zeros_us F
> >> +GLIBC_2.40 openat2 F
> >> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> >> index d9bd6a9b56..5ff3db5035 100644
> >> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> >> @@ -2781,6 +2781,7 @@ GLIBC_2.4 xdrstdio_create F
> >>  GLIBC_2.4 xencrypt F
> >>  GLIBC_2.4 xprt_register F
> >>  GLIBC_2.4 xprt_unregister F
> >> +GLIBC_2.40 openat2 F
> >>  GLIBC_2.5 __readlinkat_chk F
> >>  GLIBC_2.5 inet6_opt_append F
> >>  GLIBC_2.5 inet6_opt_find F
> >> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> >> index 439796d693..39645248af 100644
> >> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> >> @@ -2948,6 +2948,7 @@ GLIBC_2.4 sys_errlist D 0x210
> >>  GLIBC_2.4 sys_nerr D 0x4
> >>  GLIBC_2.4 unlinkat F
> >>  GLIBC_2.4 unshare F
> >> +GLIBC_2.40 openat2 F
> >>  GLIBC_2.5 __readlinkat_chk F
> >>  GLIBC_2.5 inet6_opt_append F
> >>  GLIBC_2.5 inet6_opt_find F
> >> diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> >> index 1069d3252c..2f917724de 100644
> >> --- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> >> @@ -2834,3 +2834,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
> >>  GLIBC_2.39 stdc_trailing_zeros_ul F
> >>  GLIBC_2.39 stdc_trailing_zeros_ull F
> >>  GLIBC_2.39 stdc_trailing_zeros_us F
> >> +GLIBC_2.40 openat2 F
> >> diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> >> index 17abe08c8b..6cc64f97b5 100644
> >> --- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> >> @@ -2831,3 +2831,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
> >>  GLIBC_2.39 stdc_trailing_zeros_ul F
> >>  GLIBC_2.39 stdc_trailing_zeros_ull F
> >>  GLIBC_2.39 stdc_trailing_zeros_us F
> >> +GLIBC_2.40 openat2 F
> >> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> >> index 799e508950..ae5b95bc76 100644
> >> --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> >> @@ -2909,6 +2909,7 @@ GLIBC_2.4 renameat F
> >>  GLIBC_2.4 symlinkat F
> >>  GLIBC_2.4 unlinkat F
> >>  GLIBC_2.4 unshare F
> >> +GLIBC_2.40 openat2 F
> >>  GLIBC_2.5 __readlinkat_chk F
> >>  GLIBC_2.5 inet6_opt_append F
> >>  GLIBC_2.5 inet6_opt_find F
> >> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> >> index 1c10996cbc..434e997937 100644
> >> --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> >> @@ -2907,6 +2907,7 @@ GLIBC_2.4 renameat F
> >>  GLIBC_2.4 symlinkat F
> >>  GLIBC_2.4 unlinkat F
> >>  GLIBC_2.4 unshare F
> >> +GLIBC_2.40 openat2 F
> >>  GLIBC_2.5 __readlinkat_chk F
> >>  GLIBC_2.5 inet6_opt_append F
> >>  GLIBC_2.5 inet6_opt_find F
> >> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> >> index 03d9655f26..5dc2996fcc 100644
> >> --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> >> @@ -2915,6 +2915,7 @@ GLIBC_2.4 renameat F
> >>  GLIBC_2.4 symlinkat F
> >>  GLIBC_2.4 unlinkat F
> >>  GLIBC_2.4 unshare F
> >> +GLIBC_2.40 openat2 F
> >>  GLIBC_2.5 __readlinkat_chk F
> >>  GLIBC_2.5 inet6_opt_append F
> >>  GLIBC_2.5 inet6_opt_find F
> >> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> >> index 05e402ed30..865dc5e7f1 100644
> >> --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> >> @@ -2817,6 +2817,7 @@ GLIBC_2.4 renameat F
> >>  GLIBC_2.4 symlinkat F
> >>  GLIBC_2.4 unlinkat F
> >>  GLIBC_2.4 unshare F
> >> +GLIBC_2.40 openat2 F
> >>  GLIBC_2.5 __readlinkat_chk F
> >>  GLIBC_2.5 inet6_opt_append F
> >>  GLIBC_2.5 inet6_opt_find F
> >> diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> >> index 3aa81766aa..12775fdad5 100644
> >> --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> >> @@ -2873,3 +2873,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
> >>  GLIBC_2.39 stdc_trailing_zeros_ul F
> >>  GLIBC_2.39 stdc_trailing_zeros_ull F
> >>  GLIBC_2.39 stdc_trailing_zeros_us F
> >> +GLIBC_2.40 openat2 F
> >> diff --git a/sysdeps/unix/sysv/linux/openat2.c b/sysdeps/unix/sysv/linux/openat2.c
> >> new file mode 100644
> >> index 0000000000..a2b134bab0
> >> --- /dev/null
> >> +++ b/sysdeps/unix/sysv/linux/openat2.c
> >> @@ -0,0 +1,29 @@
> >> +/* Linux openat2 syscall implementation.
> >> +   Copyright (C) 2024 Free Software Foundation, Inc.
> >> +   This file is part of the GNU C Library.
> >> +
> >> +   The GNU C Library is free software; you can redistribute it and/or
> >> +   modify it under the terms of the GNU Lesser General Public
> >> +   License as published by the Free Software Foundation; either
> >> +   version 2.1 of the License, or (at your option) any later version.
> >> +
> >> +   The GNU C Library is distributed in the hope that it will be useful,
> >> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> >> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> >> +   Lesser General Public License for more details.
> >> +
> >> +   You should have received a copy of the GNU Lesser General Public
> >> +   License along with the GNU C Library; if not, see
> >> +   <https://www.gnu.org/licenses/>.  */
> >> +
> >> +#include <fcntl.h>
> >> +#include <bits/openat2.h>
> >> +#include <sysdep-cancel.h>
> >> +
> >> +int
> >> +__openat2 (int dfd, const char *filename, struct open_how *how,
> >> +          size_t usize)
> >> +{
> >> +  return SYSCALL_CANCEL (openat2, dfd, filename, how, usize);
> >> +}
> >> +weak_alias (__openat2, openat2)
> >> diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist
> >> index c40c843aaf..2835436011 100644
> >> --- a/sysdeps/unix/sysv/linux/or1k/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist
> >> @@ -2255,3 +2255,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
> >>  GLIBC_2.39 stdc_trailing_zeros_ul F
> >>  GLIBC_2.39 stdc_trailing_zeros_ull F
> >>  GLIBC_2.39 stdc_trailing_zeros_us F
> >> +GLIBC_2.40 openat2 F
> >> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> >> index 9714305608..3b70a56944 100644
> >> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> >> @@ -3138,6 +3138,7 @@ GLIBC_2.4 wcstold F
> >>  GLIBC_2.4 wcstold_l F
> >>  GLIBC_2.4 wprintf F
> >>  GLIBC_2.4 wscanf F
> >> +GLIBC_2.40 openat2 F
> >>  GLIBC_2.5 __readlinkat_chk F
> >>  GLIBC_2.5 inet6_opt_append F
> >>  GLIBC_2.5 inet6_opt_find F
> >> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> >> index 0beb52c542..677c9a75de 100644
> >> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> >> @@ -3183,6 +3183,7 @@ GLIBC_2.4 wcstold F
> >>  GLIBC_2.4 wcstold_l F
> >>  GLIBC_2.4 wprintf F
> >>  GLIBC_2.4 wscanf F
> >> +GLIBC_2.40 openat2 F
> >>  GLIBC_2.5 __readlinkat_chk F
> >>  GLIBC_2.5 inet6_opt_append F
> >>  GLIBC_2.5 inet6_opt_find F
> >> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> >> index cfc2ebd3ec..10fc3c89dc 100644
> >> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> >> @@ -2892,6 +2892,7 @@ GLIBC_2.4 wcstold F
> >>  GLIBC_2.4 wcstold_l F
> >>  GLIBC_2.4 wprintf F
> >>  GLIBC_2.4 wscanf F
> >> +GLIBC_2.40 openat2 F
> >>  GLIBC_2.5 __readlinkat_chk F
> >>  GLIBC_2.5 inet6_opt_append F
> >>  GLIBC_2.5 inet6_opt_find F
> >> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> >> index 8c9efc5a16..713fa1d1c8 100644
> >> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> >> @@ -2968,3 +2968,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
> >>  GLIBC_2.39 stdc_trailing_zeros_ul F
> >>  GLIBC_2.39 stdc_trailing_zeros_ull F
> >>  GLIBC_2.39 stdc_trailing_zeros_us F
> >> +GLIBC_2.40 openat2 F
> >> diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> >> index 6397a9cb91..550ba877ef 100644
> >> --- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> >> @@ -2512,3 +2512,4 @@ GLIBC_2.39 stdc_trailing_zeros_ul F
> >>  GLIBC_2.39 stdc_trailing_zeros_ull F
> >>  GLIBC_2.39 stdc_trailing_zeros_us F
> >>  GLIBC_2.40 __riscv_hwprobe F
> >> +GLIBC_2.40 openat2 F
> >> diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> >> index 71bbf94f66..8bf9f309b7 100644
> >> --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> >> @@ -2712,3 +2712,4 @@ GLIBC_2.39 stdc_trailing_zeros_ul F
> >>  GLIBC_2.39 stdc_trailing_zeros_ull F
> >>  GLIBC_2.39 stdc_trailing_zeros_us F
> >>  GLIBC_2.40 __riscv_hwprobe F
> >> +GLIBC_2.40 openat2 F
> >> diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> >> index a7467e2850..08bc3d6f8b 100644
> >> --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> >> @@ -3136,6 +3136,7 @@ GLIBC_2.4 wcstold F
> >>  GLIBC_2.4 wcstold_l F
> >>  GLIBC_2.4 wprintf F
> >>  GLIBC_2.4 wscanf F
> >> +GLIBC_2.40 openat2 F
> >>  GLIBC_2.5 __readlinkat_chk F
> >>  GLIBC_2.5 inet6_opt_append F
> >>  GLIBC_2.5 inet6_opt_find F
> >> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> >> index fd1cb2972d..e25afff581 100644
> >> --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> >> @@ -2929,6 +2929,7 @@ GLIBC_2.4 wcstold F
> >>  GLIBC_2.4 wcstold_l F
> >>  GLIBC_2.4 wprintf F
> >>  GLIBC_2.4 wscanf F
> >> +GLIBC_2.40 openat2 F
> >>  GLIBC_2.5 __readlinkat_chk F
> >>  GLIBC_2.5 inet6_opt_append F
> >>  GLIBC_2.5 inet6_opt_find F
> >> diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> >> index ff6e6b1a13..499de50ee0 100644
> >> --- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> >> @@ -2828,6 +2828,7 @@ GLIBC_2.4 sys_errlist D 0x210
> >>  GLIBC_2.4 sys_nerr D 0x4
> >>  GLIBC_2.4 unlinkat F
> >>  GLIBC_2.4 unshare F
> >> +GLIBC_2.40 openat2 F
> >>  GLIBC_2.5 __readlinkat_chk F
> >>  GLIBC_2.5 inet6_opt_append F
> >>  GLIBC_2.5 inet6_opt_find F
> >> diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> >> index 449d92bbc5..bdd9c600f0 100644
> >> --- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> >> @@ -2825,6 +2825,7 @@ GLIBC_2.4 sys_errlist D 0x210
> >>  GLIBC_2.4 sys_nerr D 0x4
> >>  GLIBC_2.4 unlinkat F
> >>  GLIBC_2.4 unshare F
> >> +GLIBC_2.40 openat2 F
> >>  GLIBC_2.5 __readlinkat_chk F
> >>  GLIBC_2.5 inet6_opt_append F
> >>  GLIBC_2.5 inet6_opt_find F
> >> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> >> index e615be759a..b20dd43d47 100644
> >> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> >> @@ -3157,6 +3157,7 @@ GLIBC_2.4 wcstold F
> >>  GLIBC_2.4 wcstold_l F
> >>  GLIBC_2.4 wprintf F
> >>  GLIBC_2.4 wscanf F
> >> +GLIBC_2.40 openat2 F
> >>  GLIBC_2.5 __readlinkat_chk F
> >>  GLIBC_2.5 inet6_opt_append F
> >>  GLIBC_2.5 inet6_opt_find F
> >> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> >> index bd36431dd7..19981aa981 100644
> >> --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> >> @@ -2793,6 +2793,7 @@ GLIBC_2.4 sys_errlist D 0x430
> >>  GLIBC_2.4 sys_nerr D 0x4
> >>  GLIBC_2.4 unlinkat F
> >>  GLIBC_2.4 unshare F
> >> +GLIBC_2.40 openat2 F
> >>  GLIBC_2.5 __readlinkat_chk F
> >>  GLIBC_2.5 inet6_opt_append F
> >>  GLIBC_2.5 inet6_opt_find F
> >> diff --git a/sysdeps/unix/sysv/linux/tst-openat2-consts.py b/sysdeps/unix/sysv/linux/tst-openat2-consts.py
> >> new file mode 100755
> >> index 0000000000..1623fafd94
> >> --- /dev/null
> >> +++ b/sysdeps/unix/sysv/linux/tst-openat2-consts.py
> >> @@ -0,0 +1,63 @@
> >> +#!/usr/bin/python3
> >> +# Test that glibc's sys/openat2.h constants match the kernel's.
> >> +# Copyright (C) 2024 Free Software Foundation, Inc.
> >> +# This file is part of the GNU C Library.
> >> +#
> >> +# The GNU C Library is free software; you can redistribute it and/or
> >> +# modify it under the terms of the GNU Lesser General Public
> >> +# License as published by the Free Software Foundation; either
> >> +# version 2.1 of the License, or (at your option) any later version.
> >> +#
> >> +# The GNU C Library is distributed in the hope that it will be useful,
> >> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> >> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> >> +# Lesser General Public License for more details.
> >> +#
> >> +# You should have received a copy of the GNU Lesser General Public
> >> +# License along with the GNU C Library; if not, see
> >> +# <https://www.gnu.org/licenses/>.
> >> +
> >> +import argparse
> >> +import sys
> >> +
> >> +import glibcextract
> >> +import glibcsyscalls
> >> +
> >> +
> >> +def main():
> >> +    """The main entry point."""
> >> +    parser = argparse.ArgumentParser(
> >> +        description="Test that glibc's sys/openat2.h constants "
> >> +        "match the kernel's.")
> >> +    parser.add_argument('--cc', metavar='CC',
> >> +                        help='C compiler (including options) to use')
> >> +    args = parser.parse_args()
> >> +
> >> +    if glibcextract.compile_c_snippet(
> >> +            '#include <linux/openat2.h>',
> >> +            args.cc).returncode != 0:
> >> +        sys.exit (77)
> >> +
> >> +    linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
> >> +    # Constants in glibc were updated to match Linux v6.8.  When glibc
> >> +    # constants are updated this value should be updated to match the
> >> +    # released kernel version from which the constants were taken.
> >> +    linux_version_glibc = (6, 8)
> >> +    def check(cte, exclude=None):
> >> +        return glibcextract.compare_macro_consts(
> >> +                '#define _FCNTL_H\n'
> >> +                '#include <stdint.h>\n'
> >> +                '#include <bits/openat2.h>\n',
> >> +                '#include <asm/fcntl.h>\n'
> >> +                '#include <linux/openat2.h>\n',
> >> +                args.cc,
> >> +                cte,
> >> +                exclude,
> >> +                linux_version_glibc > linux_version_headers,
> >> +                linux_version_headers > linux_version_glibc)
> >> +
> >> +    status = check('RESOLVE.*')
> >> +    sys.exit(status)
> >> +
> >> +if __name__ == '__main__':
> >> +    main()
> >> diff --git a/sysdeps/unix/sysv/linux/tst-openat2.c b/sysdeps/unix/sysv/linux/tst-openat2.c
> >> new file mode 100644
> >> index 0000000000..d0c26f2bce
> >> --- /dev/null
> >> +++ b/sysdeps/unix/sysv/linux/tst-openat2.c
> >> @@ -0,0 +1,259 @@
> >> +/* Linux openat2 tests.
> >> +   Copyright (C) 2024 Free Software Foundation, Inc.
> >> +   This file is part of the GNU C Library.
> >> +
> >> +   The GNU C Library is free software; you can redistribute it and/or
> >> +   modify it under the terms of the GNU Lesser General Public
> >> +   License as published by the Free Software Foundation; either
> >> +   version 2.1 of the License, or (at your option) any later version.
> >> +
> >> +   The GNU C Library is distributed in the hope that it will be useful,
> >> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> >> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> >> +   Lesser General Public License for more details.
> >> +
> >> +   You should have received a copy of the GNU Lesser General Public
> >> +   License along with the GNU C Library; if not, see
> >> +   <https://www.gnu.org/licenses/>.  */
> >> +
> >> +/* openat2 always return a file descriptor in LFS mode.  */
> >> +#define _FILE_OFFSET_BITS 64
> >> +
> >> +#include <array_length.h>
> >> +#include <errno.h>
> >> +#include <fcntl.h>
> >> +#include <stdint.h>
> >> +#include <support/check.h>
> >> +#include <support/temp_file.h>
> >> +#include <support/xunistd.h>
> >> +
> >> +static int dir_fd;
> >> +
> >> +static void
> >> +do_prepare (int argc, char *argv[])
> >> +{
> >> +  char *temp_dir = support_create_temp_directory ("tst-openat2");
> >> +  dir_fd = xopen (temp_dir, O_RDONLY | O_DIRECTORY, 0);
> >> +}
> >> +#define PREPARE do_prepare
> >> +
> >> +static int
> >> +do_test_struct (void)
> >> +{
> >> +  static struct struct_test
> >> +  {
> >> +    struct open_how_ext
> >> +    {
> >> +      struct open_how inner;
> >> +      int extra1;
> >> +      int extra2;
> >> +      int extra3;
> >> +    } arg;
> >> +    size_t size;
> >> +    int err;
> >> +  } tests[] =
> >> +  {
> >> +    {
> >> +      /* Zero size.  */
> >> +      .arg.inner.flags = O_RDONLY,
> >> +      .size = 0,
> >> +      .err = EINVAL,
> >> +    },
> >> +    {
> >> +      /* Normal struct.  */
> >> +      .arg.inner.flags = O_RDONLY,
> >> +      .size = sizeof (struct open_how),
> >> +    },
> >> +    {
> >> +      /* Larger struct, zeroed out the unused values.  */
> >> +      .arg.inner.flags = O_RDONLY,
> >> +      .size = sizeof (struct open_how_ext),
> >> +    },
> >> +    {
> >> +      /* Larger struct, non-zeroed out the unused values.  */
> >> +      .arg.inner.flags = O_RDONLY,
> >> +      .arg.extra1 = 0xdeadbeef,
> >> +      .size = sizeof (struct open_how_ext),
> >> +      .err = E2BIG,
> >> +    },
> >> +    {
> >> +      /* Larger struct, non-zeroed out the unused values.  */
> >> +      .arg.inner.flags = O_RDONLY,
> >> +      .arg.extra2 = 0xdeadbeef,
> >> +      .size = sizeof (struct open_how_ext),
> >> +      .err = E2BIG,
> >> +    },
> >> +  };
> >> +
> >> +  for (struct struct_test *t = tests; t != array_end (tests); t++)
> >> +    {
> >> +      int fd = openat2 (AT_FDCWD, ".", (struct open_how *) &t->arg, t->size);
> >> +      if (fd == -1 && errno == ENOSYS)
> >> +       FAIL_UNSUPPORTED ("openat2 is not supported by the kernel");
> >> +
> >> +      if (t->err != 0)
> >> +       {
> >> +         TEST_COMPARE (fd, -1);
> >> +         TEST_COMPARE (errno, t->err);
> >> +       }
> >> +      else
> >> +       TEST_VERIFY (fd >= 0);
> >> +    }
> >> +
> >> +  return 0;
> >> +}
> >> +
> >> +static int
> >> +do_test_flags (void)
> >> +{
> >> +  static struct flag_test
> >> +  {
> >> +    struct open_how how;
> >> +    int err;
> >> +  } tests[] =
> >> +  {
> >> +    /* O_TMPFILE is incompatible with O_PATH and O_CREAT.  */
> >> +    { .how.flags = O_TMPFILE | O_PATH | O_RDWR, .err = EINVAL },
> >> +    { .how.flags = O_TMPFILE | O_CREAT | O_RDWR, .err = EINVAL },
> >> +
> >> +    /* O_PATH only permits certain other flags to be set ...  */
> >> +    { .how.flags = O_PATH | O_CLOEXEC },
> >> +    { .how.flags = O_PATH | O_DIRECTORY },
> >> +    { .how.flags = O_PATH | O_NOFOLLOW },
> >> +    /* ... and others are absolutely not permitted. */
> >> +    { .how.flags = O_PATH | O_RDWR, .err = EINVAL },
> >> +    { .how.flags = O_PATH | O_CREAT, .err = EINVAL },
> >> +    { .how.flags = O_PATH | O_EXCL, .err = EINVAL },
> >> +    { .how.flags = O_PATH | O_NOCTTY, .err = EINVAL },
> >> +    { .how.flags = O_PATH | O_DIRECT, .err = EINVAL },
> >> +
> >> +    /* ->mode must only be set with O_{CREAT,TMPFILE}. */
> >> +    { .how.flags = O_RDONLY, .how.mode = 0600, .err = EINVAL },
> >> +    { .how.flags = O_PATH,   .how.mode = 0600, .err = EINVAL },
> >> +    { .how.flags = O_CREAT,  .how.mode = 0600 },
> >> +    { .how.flags = O_TMPFILE | O_RDWR, .how.mode = 0600 },
> >> +    /* ->mode must only contain 0777 bits. */
> >> +    { .how.flags = O_CREAT, .how.mode = 0xFFFF, .err = EINVAL },
> >> +    { .how.flags = O_CREAT, .how.mode = 0xC000000000000000ULL, .err = EINVAL },
> >> +    { .how.flags = O_TMPFILE | O_RDWR, .how.mode = 0x1337, .err = EINVAL },
> >> +    { .how.flags = O_TMPFILE | O_RDWR, .how.mode = 0x0000A00000000000ULL,
> >> +      .err = EINVAL },
> >> +
> >> +    /* ->resolve flags must not conflict. */
> >> +    { .how.flags = O_RDONLY,
> >> +      .how.resolve = RESOLVE_BENEATH | RESOLVE_IN_ROOT,
> >> +      .err = EINVAL },
> >> +
> >> +    /* ->resolve must only contain RESOLVE_* flags.  */
> >> +    { .how.flags = O_RDONLY,
> >> +      .how.resolve = 0x1337, .err = EINVAL },
> >> +    { .how.flags = O_CREAT,
> >> +      .how.resolve = 0x1337, .err = EINVAL },
> >> +    { .how.flags = O_TMPFILE | O_RDWR,
> >> +      .how.resolve = 0x1337, .err = EINVAL },
> >> +    { .how.flags = O_PATH,
> >> +      .how.resolve = 0x1337, .err = EINVAL },
> >> +
> >> +    /* currently unknown upper 32 bit rejected.  */
> >> +    { .how.flags = O_RDONLY | (1ULL << 63),
> >> +      .how.resolve = 0, .err = EINVAL },
> >> +  };
> >> +
> >> +  for (struct flag_test *t = tests; t != array_end (tests); t++)
> >> +    {
> >> +      char *path;
> >> +      if (t->how.flags & O_CREAT)
> >> +       {
> >> +         int temp_fd = create_temp_file ("tst-openat2.", &path);
> >> +         TEST_VERIFY_EXIT (temp_fd != -1);
> >> +         xunlink (path);
> >> +       }
> >> +      else
> >> +       path = (char *) ".";
> >> +
> >> +      int fd = openat2 (AT_FDCWD, path, &t->how, sizeof (struct open_how));
> >> +      if (fd != 0 && errno == EOPNOTSUPP)
> >> +       {
> >> +         /* Skip the testcase if FS does not support the operation (e.g.
> >> +            valid O_TMPFILE on NFS).  */
> >> +         continue;
> >> +       }
> >> +
> >> +      if (t->err != 0)
> >> +       {
> >> +         TEST_COMPARE (fd, -1);
> >> +         TEST_COMPARE (errno, t->err);
> >> +       }
> >> +      else
> >> +       TEST_VERIFY (fd >= 0);
> >> +    }
> >> +
> >> +  return 0;
> >> +}
> >> +
> >> +static int
> >> +do_test_basic (void)
> >> +{
> >> +  int fd;
> >> +
> >> +  fd = openat2 (dir_fd,
> >> +               "some-file",
> >> +               &(struct open_how)
> >> +               {
> >> +                 .flags = O_CREAT|O_RDWR|O_EXCL,
> >> +                 .mode = 0666,
> >> +               },
> >> +               sizeof (struct open_how));
> >> +  TEST_VERIFY (fd != -1);
> >> +
> >> +  xwrite (fd, "hello", 5);
> >> +
> >> +  /* Before closing the file, try using this file descriptor to open
> >> +     another file.  This must fail.  */
> >> +  {
> >> +    int fd2 = openat2 (fd,
> >> +                      "should-not-work",
> >> +                      &(struct open_how)
> >> +                      {
> >> +                        .flags = O_CREAT|O_RDWR|O_EXCL,
> >> +                        .mode = 0666,
> >> +                      },
> >> +                      sizeof (struct open_how));
> >> +    TEST_COMPARE (fd2, -1);
> >> +    TEST_COMPARE (errno, ENOTDIR);
> >> +  }
> >> +
> >> +  /* Remove the created file.  */
> >> +  int cwdfd = xopen (".", O_RDONLY | O_DIRECTORY, 0);
> >> +  TEST_COMPARE (fchdir (dir_fd), 0);
> >> +  xunlink ("some-file");
> >> +  TEST_COMPARE (fchdir (cwdfd), 0);
> >> +
> >> +  xclose (dir_fd);
> >> +  xclose (cwdfd);
> >> +
> >> +  fd = openat2 (dir_fd,
> >> +               "some-file",
> >> +               &(struct open_how)
> >> +               {
> >> +                 .flags = O_CREAT|O_RDWR|O_EXCL,
> >> +                 .mode = 0666,
> >> +               },
> >> +               sizeof (struct open_how));
> >> +  TEST_COMPARE (fd, -1);
> >> +  TEST_COMPARE (errno, EBADF);
> >> +
> >> +  return 0;
> >> +}
> >> +
> >> +static int
> >> +do_test (void)
> >> +{
> >> +  do_test_struct ();
> >> +  do_test_flags ();
> >> +  do_test_basic ();
> >> +
> >> +  return 0;
> >> +}
> >> +
> >> +#include <support/test-driver.c>
> >> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> >> index aea7848ed6..a7f177c8a8 100644
> >> --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> >> @@ -2744,6 +2744,7 @@ GLIBC_2.4 sys_errlist D 0x420
> >>  GLIBC_2.4 sys_nerr D 0x4
> >>  GLIBC_2.4 unlinkat F
> >>  GLIBC_2.4 unshare F
> >> +GLIBC_2.40 openat2 F
> >>  GLIBC_2.5 __readlinkat_chk F
> >>  GLIBC_2.5 inet6_opt_append F
> >>  GLIBC_2.5 inet6_opt_find F
> >> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> >> index 4ab3681914..00dfc8f1e7 100644
> >> --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> >> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> >> @@ -2763,3 +2763,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
> >>  GLIBC_2.39 stdc_trailing_zeros_ul F
> >>  GLIBC_2.39 stdc_trailing_zeros_ull F
> >>  GLIBC_2.39 stdc_trailing_zeros_us F
> >> +GLIBC_2.40 openat2 F
> >> --
> >> 2.34.1
> >>
Adhemerval Zanella April 25, 2024, 2 p.m. UTC | #4
On 24/04/24 18:18, enh wrote:
> On Wed, Apr 24, 2024 at 11:05 AM Adhemerval Zanella Netto
> <adhemerval.zanella@linaro.org> wrote:
>>
>> That's a good question, since we currently do not export any kernel interface
>> which this new struct/size argument passing (we do use clone3, but it is
>> just internally). For a libc/kernel interface, it should not matter; but from
>> a libc exported symbol we indeed need to be more careful.
>>
>> From a glibc perpectiveI think we will need to *not* include kernel UAPI header,
>> remove the size from the wrapper, and add some slack size on open_how for
>> future extension.  It makes open_how extensions to not require new symbol
>> version in the near future (similar to what was done for statx).
> 
> i think statx did that _in uapi_, no? there's already padding
> upstream. (that's a much better way to do these things from a libc
> perspective; if someone talks to the kernel folks, it's worth trying
> to encourage them to do more of that, and less of the openat2() or
> sched_setattr().)

Yes, the statx added some spare fields because it does not have the extra
size parameter and an statx extension that extends further will require
another syscall (this is the same for sched_setattr). The openat2 approach 
is not bad, it solves this issue.

This new kernel interface also solves another other historical problem:
it allows sizes larger than current supported as long extra fields are 
zeroed and returns EINVAL otherwise.  So I think is unlikely kernel will
add spare field on open_how, it only ads extra complexity for the kABI.

So for glibc I think it would still be better to add the spare fields, 
mainly to avoid the need to possible add new symbol versions if it requires 
to pick the struct for a eventual struct extension.

> 
>> It would make the libc and kernel version not easily interchangeable (which
>> some users do want on some cases).
>>
>> On 24/04/24 14:42, enh wrote:
>>> doesn't glibc worry about types like this, where the size can change?
>>> that presents a problem for code passing those types around. do you
>>> require that all the code in a process be compiled with the exact same
>>> headers?
>>>
>>> On Wed, Apr 24, 2024 at 10:38 AM Adhemerval Zanella
>>> <adhemerval.zanella@linaro.org> wrote:
>>>>
>>>> It was added on Linux 5.6, as an extension of openat.  Different than
>>>> other open-like functions, the kernel only provides the LFS variant (so
>>>> files larger than 4GB always succeed, as other functions with offset
>>>> larger than off_t).  Similar to other open functions, the new symbol is
>>>> a cancellable entrypoint.
>>>>
>>>> The test case added only stresses some of the syscalls provided
>>>> functionalities and it is based on an existent kernel self-test.  Since
>>>> the prototype does not use variadic arguments, there is no need to add a
>>>> fortify wrapper to catch wrong usages.
>>>>
>>>> Checked on x86_64-linux-gnu.
>>>> ---
>>>>  NEWS                                          |   4 +
>>>>  sysdeps/unix/sysv/linux/Makefile              |  14 +
>>>>  sysdeps/unix/sysv/linux/Versions              |   3 +
>>>>  sysdeps/unix/sysv/linux/aarch64/libc.abilist  |   1 +
>>>>  sysdeps/unix/sysv/linux/alpha/libc.abilist    |   1 +
>>>>  sysdeps/unix/sysv/linux/arc/libc.abilist      |   1 +
>>>>  sysdeps/unix/sysv/linux/arm/be/libc.abilist   |   1 +
>>>>  sysdeps/unix/sysv/linux/arm/le/libc.abilist   |   1 +
>>>>  sysdeps/unix/sysv/linux/bits/fcntl-linux.h    |  22 ++
>>>>  sysdeps/unix/sysv/linux/bits/openat2.h        |  61 +++++
>>>>  sysdeps/unix/sysv/linux/csky/libc.abilist     |   1 +
>>>>  sysdeps/unix/sysv/linux/hppa/libc.abilist     |   1 +
>>>>  sysdeps/unix/sysv/linux/i386/libc.abilist     |   1 +
>>>>  .../sysv/linux/loongarch/lp64/libc.abilist    |   1 +
>>>>  .../sysv/linux/m68k/coldfire/libc.abilist     |   1 +
>>>>  .../unix/sysv/linux/m68k/m680x0/libc.abilist  |   1 +
>>>>  .../sysv/linux/microblaze/be/libc.abilist     |   1 +
>>>>  .../sysv/linux/microblaze/le/libc.abilist     |   1 +
>>>>  .../sysv/linux/mips/mips32/fpu/libc.abilist   |   1 +
>>>>  .../sysv/linux/mips/mips32/nofpu/libc.abilist |   1 +
>>>>  .../sysv/linux/mips/mips64/n32/libc.abilist   |   1 +
>>>>  .../sysv/linux/mips/mips64/n64/libc.abilist   |   1 +
>>>>  sysdeps/unix/sysv/linux/nios2/libc.abilist    |   1 +
>>>>  sysdeps/unix/sysv/linux/openat2.c             |  29 ++
>>>>  sysdeps/unix/sysv/linux/or1k/libc.abilist     |   1 +
>>>>  .../linux/powerpc/powerpc32/fpu/libc.abilist  |   1 +
>>>>  .../powerpc/powerpc32/nofpu/libc.abilist      |   1 +
>>>>  .../linux/powerpc/powerpc64/be/libc.abilist   |   1 +
>>>>  .../linux/powerpc/powerpc64/le/libc.abilist   |   1 +
>>>>  .../unix/sysv/linux/riscv/rv32/libc.abilist   |   1 +
>>>>  .../unix/sysv/linux/riscv/rv64/libc.abilist   |   1 +
>>>>  .../unix/sysv/linux/s390/s390-32/libc.abilist |   1 +
>>>>  .../unix/sysv/linux/s390/s390-64/libc.abilist |   1 +
>>>>  sysdeps/unix/sysv/linux/sh/be/libc.abilist    |   1 +
>>>>  sysdeps/unix/sysv/linux/sh/le/libc.abilist    |   1 +
>>>>  .../sysv/linux/sparc/sparc32/libc.abilist     |   1 +
>>>>  .../sysv/linux/sparc/sparc64/libc.abilist     |   1 +
>>>>  sysdeps/unix/sysv/linux/tst-openat2-consts.py |  63 +++++
>>>>  sysdeps/unix/sysv/linux/tst-openat2.c         | 259 ++++++++++++++++++
>>>>  .../unix/sysv/linux/x86_64/64/libc.abilist    |   1 +
>>>>  .../unix/sysv/linux/x86_64/x32/libc.abilist   |   1 +
>>>>  41 files changed, 488 insertions(+)
>>>>  create mode 100644 sysdeps/unix/sysv/linux/bits/openat2.h
>>>>  create mode 100644 sysdeps/unix/sysv/linux/openat2.c
>>>>  create mode 100755 sysdeps/unix/sysv/linux/tst-openat2-consts.py
>>>>  create mode 100644 sysdeps/unix/sysv/linux/tst-openat2.c
>>>>
>>>> diff --git a/NEWS b/NEWS
>>>> index cf6078cf20..eaaa02cb4e 100644
>>>> --- a/NEWS
>>>> +++ b/NEWS
>>>> @@ -26,6 +26,10 @@ Major new features:
>>>>    more extensive verification tests for AT_SECURE programs and not meant to
>>>>    be a security feature.
>>>>
>>>> +* On Linux, the openat2 function has been added.  It is an extension of
>>>> +  openat and provides a superset of its functionality.  It is supported only
>>>> +  in LFS mode and as other open like it is a cancellable entrypoint.
>>>> +
>>>>  Deprecated and removed features, and other changes affecting compatibility:
>>>>
>>>>  * Architectures which use a 32-bit seconds-since-epoch field in struct
>>>> diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
>>>> index 415aa1f14d..4ae8ec6dc6 100644
>>>> --- a/sysdeps/unix/sysv/linux/Makefile
>>>> +++ b/sysdeps/unix/sysv/linux/Makefile
>>>> @@ -133,6 +133,7 @@ sysdep_headers += \
>>>>    bits/mman-linux.h \
>>>>    bits/mman-map-flags-generic.h \
>>>>    bits/mman-shared.h \
>>>> +  bits/openat2.h \
>>>>    bits/procfs-extra.h \
>>>>    bits/procfs-id.h \
>>>>    bits/procfs-prregset.h \
>>>> @@ -591,6 +592,7 @@ sysdep_routines += \
>>>>    internal_statvfs \
>>>>    open64_nocancel \
>>>>    open_nocancel \
>>>> +  openat2 \
>>>>    openat64_nocancel \
>>>>    openat_nocancel \
>>>>    pread64_nocancel \
>>>> @@ -611,7 +613,19 @@ tests += \
>>>>    tst-fallocate64 \
>>>>    tst-getcwd-smallbuff \
>>>>    tst-o_path-locks \
>>>> +  tst-openat2 \
>>>>    # tests
>>>> +
>>>> +tests-special += \
>>>> +  $(objpfx)tst-openat2-consts.out \
>>>> +  # tests-special
>>>> +$(objpfx)tst-openat2-consts.out: ../sysdeps/unix/sysv/linux/tst-openat2-consts.py
>>>> +       $(sysdeps-linux-python) \
>>>> +         ../sysdeps/unix/sysv/linux/tst-openat2-consts.py \
>>>> +           $(sysdeps-linux-python-cc) \
>>>> +         < /dev/null > $@ 2>&1; $(evaluate-test)
>>>> +$(objpfx)tst-openat2-consts.out: $(sysdeps-linux-python-deps)
>>>> +
>>>>  endif
>>>>
>>>>  ifeq ($(subdir),elf)
>>>> diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions
>>>> index 268ba1b6ac..65da2b617a 100644
>>>> --- a/sysdeps/unix/sysv/linux/Versions
>>>> +++ b/sysdeps/unix/sysv/linux/Versions
>>>> @@ -328,6 +328,9 @@ libc {
>>>>      posix_spawnattr_getcgroup_np;
>>>>      posix_spawnattr_setcgroup_np;
>>>>    }
>>>> +  GLIBC_2.40 {
>>>> +    openat2;
>>>> +  }
>>>>    GLIBC_PRIVATE {
>>>>      # functions used in other libraries
>>>>      __syscall_rt_sigqueueinfo;
>>>> diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
>>>> index 68eeca1c08..0b9bd8ae62 100644
>>>> --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
>>>> @@ -2748,3 +2748,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
>>>>  GLIBC_2.39 stdc_trailing_zeros_ul F
>>>>  GLIBC_2.39 stdc_trailing_zeros_ull F
>>>>  GLIBC_2.39 stdc_trailing_zeros_us F
>>>> +GLIBC_2.40 openat2 F
>>>> diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
>>>> index 34c187b721..c0bd27d617 100644
>>>> --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
>>>> @@ -3095,6 +3095,7 @@ GLIBC_2.4 wcstold F
>>>>  GLIBC_2.4 wcstold_l F
>>>>  GLIBC_2.4 wprintf F
>>>>  GLIBC_2.4 wscanf F
>>>> +GLIBC_2.40 openat2 F
>>>>  GLIBC_2.5 __readlinkat_chk F
>>>>  GLIBC_2.5 inet6_opt_append F
>>>>  GLIBC_2.5 inet6_opt_find F
>>>> diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
>>>> index 916c18ea94..965438e7a7 100644
>>>> --- a/sysdeps/unix/sysv/linux/arc/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
>>>> @@ -2509,3 +2509,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
>>>>  GLIBC_2.39 stdc_trailing_zeros_ul F
>>>>  GLIBC_2.39 stdc_trailing_zeros_ull F
>>>>  GLIBC_2.39 stdc_trailing_zeros_us F
>>>> +GLIBC_2.40 openat2 F
>>>> diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
>>>> index ea95de282a..e69ed8c903 100644
>>>> --- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
>>>> @@ -2801,6 +2801,7 @@ GLIBC_2.4 xdrstdio_create F
>>>>  GLIBC_2.4 xencrypt F
>>>>  GLIBC_2.4 xprt_register F
>>>>  GLIBC_2.4 xprt_unregister F
>>>> +GLIBC_2.40 openat2 F
>>>>  GLIBC_2.5 __readlinkat_chk F
>>>>  GLIBC_2.5 inet6_opt_append F
>>>>  GLIBC_2.5 inet6_opt_find F
>>>> diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
>>>> index 1cdbc983e1..70fd425869 100644
>>>> --- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
>>>> @@ -2798,6 +2798,7 @@ GLIBC_2.4 xdrstdio_create F
>>>>  GLIBC_2.4 xencrypt F
>>>>  GLIBC_2.4 xprt_register F
>>>>  GLIBC_2.4 xprt_unregister F
>>>> +GLIBC_2.40 openat2 F
>>>>  GLIBC_2.5 __readlinkat_chk F
>>>>  GLIBC_2.5 inet6_opt_append F
>>>>  GLIBC_2.5 inet6_opt_find F
>>>> diff --git a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
>>>> index 628612b885..279aa2b8eb 100644
>>>> --- a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
>>>> +++ b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
>>>> @@ -451,6 +451,28 @@ extern int name_to_handle_at (int __dfd, const char *__name,
>>>>  extern int open_by_handle_at (int __mountdirfd, struct file_handle *__handle,
>>>>                               int __flags);
>>>>
>>>> +#ifdef __has_include
>>>> +# if __has_include ("linux/openat2.h")
>>>> +#  include "linux/openat2.h"
>>>> +#  define __glibc_has_open_how 1
>>>> +# endif
>>>> +#endif
>>>> +
>>>> +#include <bits/openat2.h>
>>>> +
>>>> +/* Similar to `openat' but the arguments are packed on HOW with the size
>>>> +   USIZE.  If flags and mode from HOW are non-zero, then openat2 operates
>>>> +   like openat.
>>>> +
>>>> +   Unlike openat2, unknown or invalid flags result in an error (EINVAL),
>>>> +   rather than being ignored.  The mode must be zero unless one O_CREAT
>>>> +   or O_TMPFILE are set.
>>>> +
>>>> +   The kernel does not support legacy non-LFS interface.  */
>>>> +extern int openat2 (int __dfd, const char *__filename, struct open_how *__how,
>>>> +                   size_t __usize)
>>>> +     __nonnull ((2, 3));
>>>> +
>>>>  #endif /* use GNU */
>>>>
>>>>  __END_DECLS
>>>> diff --git a/sysdeps/unix/sysv/linux/bits/openat2.h b/sysdeps/unix/sysv/linux/bits/openat2.h
>>>> new file mode 100644
>>>> index 0000000000..a07984dace
>>>> --- /dev/null
>>>> +++ b/sysdeps/unix/sysv/linux/bits/openat2.h
>>>> @@ -0,0 +1,61 @@
>>>> +/* openat2 definition.  Linux specific.
>>>> +   Copyright (C) 2024 Free Software Foundation, Inc.
>>>> +   This file is part of the GNU C Library.
>>>> +
>>>> +   The GNU C Library is free software; you can redistribute it and/or
>>>> +   modify it under the terms of the GNU Lesser General Public
>>>> +   License as published by the Free Software Foundation; either
>>>> +   version 2.1 of the License, or (at your option) any later version.
>>>> +
>>>> +   The GNU C Library is distributed in the hope that it will be useful,
>>>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>>> +   Lesser General Public License for more details.
>>>> +
>>>> +   You should have received a copy of the GNU Lesser General Public
>>>> +   License along with the GNU C Library; if not, see
>>>> +   <https://www.gnu.org/licenses/>.  */
>>>> +
>>>> +#ifndef        _FCNTL_H
>>>> +# error "Never use <bits/openat2.h> directly; include <fcntl.h> instead."
>>>> +#endif
>>>> +
>>>> +#ifndef __glibc_has_open_how
>>>> +/* Arguments for how openat2 should open the target path.  */
>>>> +struct open_how
>>>> +{
>>>> +  __uint64_t flags;
>>>> +  __uint64_t mode;
>>>> +  __uint64_t resolve;
>>>> +};
>>>> +#endif
>>>> +
>>>> +/* how->resolve flags for openat2. */
>>>> +#ifndef RESOLVE_NO_XDEV
>>>> +# define RESOLVE_NO_XDEV       0x01 /* Block mount-point crossings
>>>> +                                       (includes bind-mounts).  */
>>>> +#endif
>>>> +#ifndef RESOLVE_NO_MAGICLINKS
>>>> +# define RESOLVE_NO_MAGICLINKS 0x02 /* Block traversal through procfs-style
>>>> +                                       "magic-links".  */
>>>> +#endif
>>>> +#ifndef RESOLVE_NO_SYMLINKS
>>>> +# define RESOLVE_NO_SYMLINKS   0x04 /* Block traversal through all symlinks
>>>> +                                       (implies OEXT_NO_MAGICLINKS).  */
>>>> +#endif
>>>> +#ifndef RESOLVE_BENEATH
>>>> +# define RESOLVE_BENEATH       0x08 /* Block "lexical" trickery like
>>>> +                                       "..", symlinks, and absolute
>>>> +                                       paths which escape the dirfd.  */
>>>> +#endif
>>>> +#ifndef RESOLVE_IN_ROOT
>>>> +# define RESOLVE_IN_ROOT       0x10 /* Make all jumps to "/" and ".."
>>>> +                                       be scoped inside the dirfd
>>>> +                                       (similar to chroot).  */
>>>> +#endif
>>>> +#ifndef RESOLVE_CACHED
>>>> +# define RESOLVE_CACHED                0x20 /* Only complete if resolution can be
>>>> +                                       completed through cached lookup. May
>>>> +                                       return -EAGAIN if that's not
>>>> +                                       possible.  */
>>>> +#endif
>>>> diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
>>>> index 96d45961e2..c81ea43dc1 100644
>>>> --- a/sysdeps/unix/sysv/linux/csky/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
>>>> @@ -2785,3 +2785,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
>>>>  GLIBC_2.39 stdc_trailing_zeros_ul F
>>>>  GLIBC_2.39 stdc_trailing_zeros_ull F
>>>>  GLIBC_2.39 stdc_trailing_zeros_us F
>>>> +GLIBC_2.40 openat2 F
>>>> diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
>>>> index fbcd60c2b3..23eec25d8a 100644
>>>> --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
>>>> @@ -2821,6 +2821,7 @@ GLIBC_2.4 sys_errlist D 0x400
>>>>  GLIBC_2.4 sys_nerr D 0x4
>>>>  GLIBC_2.4 unlinkat F
>>>>  GLIBC_2.4 unshare F
>>>> +GLIBC_2.40 openat2 F
>>>>  GLIBC_2.5 __readlinkat_chk F
>>>>  GLIBC_2.5 inet6_opt_append F
>>>>  GLIBC_2.5 inet6_opt_find F
>>>> diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
>>>> index c989b433c0..4ce2afb147 100644
>>>> --- a/sysdeps/unix/sysv/linux/i386/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
>>>> @@ -3005,6 +3005,7 @@ GLIBC_2.4 sys_errlist D 0x210
>>>>  GLIBC_2.4 sys_nerr D 0x4
>>>>  GLIBC_2.4 unlinkat F
>>>>  GLIBC_2.4 unshare F
>>>> +GLIBC_2.40 openat2 F
>>>>  GLIBC_2.5 __readlinkat_chk F
>>>>  GLIBC_2.5 inet6_opt_append F
>>>>  GLIBC_2.5 inet6_opt_find F
>>>> diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
>>>> index 0023ec1fa1..be76251b28 100644
>>>> --- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
>>>> @@ -2269,3 +2269,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
>>>>  GLIBC_2.39 stdc_trailing_zeros_ul F
>>>>  GLIBC_2.39 stdc_trailing_zeros_ull F
>>>>  GLIBC_2.39 stdc_trailing_zeros_us F
>>>> +GLIBC_2.40 openat2 F
>>>> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
>>>> index d9bd6a9b56..5ff3db5035 100644
>>>> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
>>>> @@ -2781,6 +2781,7 @@ GLIBC_2.4 xdrstdio_create F
>>>>  GLIBC_2.4 xencrypt F
>>>>  GLIBC_2.4 xprt_register F
>>>>  GLIBC_2.4 xprt_unregister F
>>>> +GLIBC_2.40 openat2 F
>>>>  GLIBC_2.5 __readlinkat_chk F
>>>>  GLIBC_2.5 inet6_opt_append F
>>>>  GLIBC_2.5 inet6_opt_find F
>>>> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
>>>> index 439796d693..39645248af 100644
>>>> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
>>>> @@ -2948,6 +2948,7 @@ GLIBC_2.4 sys_errlist D 0x210
>>>>  GLIBC_2.4 sys_nerr D 0x4
>>>>  GLIBC_2.4 unlinkat F
>>>>  GLIBC_2.4 unshare F
>>>> +GLIBC_2.40 openat2 F
>>>>  GLIBC_2.5 __readlinkat_chk F
>>>>  GLIBC_2.5 inet6_opt_append F
>>>>  GLIBC_2.5 inet6_opt_find F
>>>> diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
>>>> index 1069d3252c..2f917724de 100644
>>>> --- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
>>>> @@ -2834,3 +2834,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
>>>>  GLIBC_2.39 stdc_trailing_zeros_ul F
>>>>  GLIBC_2.39 stdc_trailing_zeros_ull F
>>>>  GLIBC_2.39 stdc_trailing_zeros_us F
>>>> +GLIBC_2.40 openat2 F
>>>> diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
>>>> index 17abe08c8b..6cc64f97b5 100644
>>>> --- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
>>>> @@ -2831,3 +2831,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
>>>>  GLIBC_2.39 stdc_trailing_zeros_ul F
>>>>  GLIBC_2.39 stdc_trailing_zeros_ull F
>>>>  GLIBC_2.39 stdc_trailing_zeros_us F
>>>> +GLIBC_2.40 openat2 F
>>>> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
>>>> index 799e508950..ae5b95bc76 100644
>>>> --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
>>>> @@ -2909,6 +2909,7 @@ GLIBC_2.4 renameat F
>>>>  GLIBC_2.4 symlinkat F
>>>>  GLIBC_2.4 unlinkat F
>>>>  GLIBC_2.4 unshare F
>>>> +GLIBC_2.40 openat2 F
>>>>  GLIBC_2.5 __readlinkat_chk F
>>>>  GLIBC_2.5 inet6_opt_append F
>>>>  GLIBC_2.5 inet6_opt_find F
>>>> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
>>>> index 1c10996cbc..434e997937 100644
>>>> --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
>>>> @@ -2907,6 +2907,7 @@ GLIBC_2.4 renameat F
>>>>  GLIBC_2.4 symlinkat F
>>>>  GLIBC_2.4 unlinkat F
>>>>  GLIBC_2.4 unshare F
>>>> +GLIBC_2.40 openat2 F
>>>>  GLIBC_2.5 __readlinkat_chk F
>>>>  GLIBC_2.5 inet6_opt_append F
>>>>  GLIBC_2.5 inet6_opt_find F
>>>> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
>>>> index 03d9655f26..5dc2996fcc 100644
>>>> --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
>>>> @@ -2915,6 +2915,7 @@ GLIBC_2.4 renameat F
>>>>  GLIBC_2.4 symlinkat F
>>>>  GLIBC_2.4 unlinkat F
>>>>  GLIBC_2.4 unshare F
>>>> +GLIBC_2.40 openat2 F
>>>>  GLIBC_2.5 __readlinkat_chk F
>>>>  GLIBC_2.5 inet6_opt_append F
>>>>  GLIBC_2.5 inet6_opt_find F
>>>> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
>>>> index 05e402ed30..865dc5e7f1 100644
>>>> --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
>>>> @@ -2817,6 +2817,7 @@ GLIBC_2.4 renameat F
>>>>  GLIBC_2.4 symlinkat F
>>>>  GLIBC_2.4 unlinkat F
>>>>  GLIBC_2.4 unshare F
>>>> +GLIBC_2.40 openat2 F
>>>>  GLIBC_2.5 __readlinkat_chk F
>>>>  GLIBC_2.5 inet6_opt_append F
>>>>  GLIBC_2.5 inet6_opt_find F
>>>> diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
>>>> index 3aa81766aa..12775fdad5 100644
>>>> --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
>>>> @@ -2873,3 +2873,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
>>>>  GLIBC_2.39 stdc_trailing_zeros_ul F
>>>>  GLIBC_2.39 stdc_trailing_zeros_ull F
>>>>  GLIBC_2.39 stdc_trailing_zeros_us F
>>>> +GLIBC_2.40 openat2 F
>>>> diff --git a/sysdeps/unix/sysv/linux/openat2.c b/sysdeps/unix/sysv/linux/openat2.c
>>>> new file mode 100644
>>>> index 0000000000..a2b134bab0
>>>> --- /dev/null
>>>> +++ b/sysdeps/unix/sysv/linux/openat2.c
>>>> @@ -0,0 +1,29 @@
>>>> +/* Linux openat2 syscall implementation.
>>>> +   Copyright (C) 2024 Free Software Foundation, Inc.
>>>> +   This file is part of the GNU C Library.
>>>> +
>>>> +   The GNU C Library is free software; you can redistribute it and/or
>>>> +   modify it under the terms of the GNU Lesser General Public
>>>> +   License as published by the Free Software Foundation; either
>>>> +   version 2.1 of the License, or (at your option) any later version.
>>>> +
>>>> +   The GNU C Library is distributed in the hope that it will be useful,
>>>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>>> +   Lesser General Public License for more details.
>>>> +
>>>> +   You should have received a copy of the GNU Lesser General Public
>>>> +   License along with the GNU C Library; if not, see
>>>> +   <https://www.gnu.org/licenses/>.  */
>>>> +
>>>> +#include <fcntl.h>
>>>> +#include <bits/openat2.h>
>>>> +#include <sysdep-cancel.h>
>>>> +
>>>> +int
>>>> +__openat2 (int dfd, const char *filename, struct open_how *how,
>>>> +          size_t usize)
>>>> +{
>>>> +  return SYSCALL_CANCEL (openat2, dfd, filename, how, usize);
>>>> +}
>>>> +weak_alias (__openat2, openat2)
>>>> diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist
>>>> index c40c843aaf..2835436011 100644
>>>> --- a/sysdeps/unix/sysv/linux/or1k/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist
>>>> @@ -2255,3 +2255,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
>>>>  GLIBC_2.39 stdc_trailing_zeros_ul F
>>>>  GLIBC_2.39 stdc_trailing_zeros_ull F
>>>>  GLIBC_2.39 stdc_trailing_zeros_us F
>>>> +GLIBC_2.40 openat2 F
>>>> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
>>>> index 9714305608..3b70a56944 100644
>>>> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
>>>> @@ -3138,6 +3138,7 @@ GLIBC_2.4 wcstold F
>>>>  GLIBC_2.4 wcstold_l F
>>>>  GLIBC_2.4 wprintf F
>>>>  GLIBC_2.4 wscanf F
>>>> +GLIBC_2.40 openat2 F
>>>>  GLIBC_2.5 __readlinkat_chk F
>>>>  GLIBC_2.5 inet6_opt_append F
>>>>  GLIBC_2.5 inet6_opt_find F
>>>> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
>>>> index 0beb52c542..677c9a75de 100644
>>>> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
>>>> @@ -3183,6 +3183,7 @@ GLIBC_2.4 wcstold F
>>>>  GLIBC_2.4 wcstold_l F
>>>>  GLIBC_2.4 wprintf F
>>>>  GLIBC_2.4 wscanf F
>>>> +GLIBC_2.40 openat2 F
>>>>  GLIBC_2.5 __readlinkat_chk F
>>>>  GLIBC_2.5 inet6_opt_append F
>>>>  GLIBC_2.5 inet6_opt_find F
>>>> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
>>>> index cfc2ebd3ec..10fc3c89dc 100644
>>>> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
>>>> @@ -2892,6 +2892,7 @@ GLIBC_2.4 wcstold F
>>>>  GLIBC_2.4 wcstold_l F
>>>>  GLIBC_2.4 wprintf F
>>>>  GLIBC_2.4 wscanf F
>>>> +GLIBC_2.40 openat2 F
>>>>  GLIBC_2.5 __readlinkat_chk F
>>>>  GLIBC_2.5 inet6_opt_append F
>>>>  GLIBC_2.5 inet6_opt_find F
>>>> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
>>>> index 8c9efc5a16..713fa1d1c8 100644
>>>> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
>>>> @@ -2968,3 +2968,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
>>>>  GLIBC_2.39 stdc_trailing_zeros_ul F
>>>>  GLIBC_2.39 stdc_trailing_zeros_ull F
>>>>  GLIBC_2.39 stdc_trailing_zeros_us F
>>>> +GLIBC_2.40 openat2 F
>>>> diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
>>>> index 6397a9cb91..550ba877ef 100644
>>>> --- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
>>>> @@ -2512,3 +2512,4 @@ GLIBC_2.39 stdc_trailing_zeros_ul F
>>>>  GLIBC_2.39 stdc_trailing_zeros_ull F
>>>>  GLIBC_2.39 stdc_trailing_zeros_us F
>>>>  GLIBC_2.40 __riscv_hwprobe F
>>>> +GLIBC_2.40 openat2 F
>>>> diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
>>>> index 71bbf94f66..8bf9f309b7 100644
>>>> --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
>>>> @@ -2712,3 +2712,4 @@ GLIBC_2.39 stdc_trailing_zeros_ul F
>>>>  GLIBC_2.39 stdc_trailing_zeros_ull F
>>>>  GLIBC_2.39 stdc_trailing_zeros_us F
>>>>  GLIBC_2.40 __riscv_hwprobe F
>>>> +GLIBC_2.40 openat2 F
>>>> diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
>>>> index a7467e2850..08bc3d6f8b 100644
>>>> --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
>>>> @@ -3136,6 +3136,7 @@ GLIBC_2.4 wcstold F
>>>>  GLIBC_2.4 wcstold_l F
>>>>  GLIBC_2.4 wprintf F
>>>>  GLIBC_2.4 wscanf F
>>>> +GLIBC_2.40 openat2 F
>>>>  GLIBC_2.5 __readlinkat_chk F
>>>>  GLIBC_2.5 inet6_opt_append F
>>>>  GLIBC_2.5 inet6_opt_find F
>>>> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
>>>> index fd1cb2972d..e25afff581 100644
>>>> --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
>>>> @@ -2929,6 +2929,7 @@ GLIBC_2.4 wcstold F
>>>>  GLIBC_2.4 wcstold_l F
>>>>  GLIBC_2.4 wprintf F
>>>>  GLIBC_2.4 wscanf F
>>>> +GLIBC_2.40 openat2 F
>>>>  GLIBC_2.5 __readlinkat_chk F
>>>>  GLIBC_2.5 inet6_opt_append F
>>>>  GLIBC_2.5 inet6_opt_find F
>>>> diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
>>>> index ff6e6b1a13..499de50ee0 100644
>>>> --- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
>>>> @@ -2828,6 +2828,7 @@ GLIBC_2.4 sys_errlist D 0x210
>>>>  GLIBC_2.4 sys_nerr D 0x4
>>>>  GLIBC_2.4 unlinkat F
>>>>  GLIBC_2.4 unshare F
>>>> +GLIBC_2.40 openat2 F
>>>>  GLIBC_2.5 __readlinkat_chk F
>>>>  GLIBC_2.5 inet6_opt_append F
>>>>  GLIBC_2.5 inet6_opt_find F
>>>> diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
>>>> index 449d92bbc5..bdd9c600f0 100644
>>>> --- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
>>>> @@ -2825,6 +2825,7 @@ GLIBC_2.4 sys_errlist D 0x210
>>>>  GLIBC_2.4 sys_nerr D 0x4
>>>>  GLIBC_2.4 unlinkat F
>>>>  GLIBC_2.4 unshare F
>>>> +GLIBC_2.40 openat2 F
>>>>  GLIBC_2.5 __readlinkat_chk F
>>>>  GLIBC_2.5 inet6_opt_append F
>>>>  GLIBC_2.5 inet6_opt_find F
>>>> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
>>>> index e615be759a..b20dd43d47 100644
>>>> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
>>>> @@ -3157,6 +3157,7 @@ GLIBC_2.4 wcstold F
>>>>  GLIBC_2.4 wcstold_l F
>>>>  GLIBC_2.4 wprintf F
>>>>  GLIBC_2.4 wscanf F
>>>> +GLIBC_2.40 openat2 F
>>>>  GLIBC_2.5 __readlinkat_chk F
>>>>  GLIBC_2.5 inet6_opt_append F
>>>>  GLIBC_2.5 inet6_opt_find F
>>>> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
>>>> index bd36431dd7..19981aa981 100644
>>>> --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
>>>> @@ -2793,6 +2793,7 @@ GLIBC_2.4 sys_errlist D 0x430
>>>>  GLIBC_2.4 sys_nerr D 0x4
>>>>  GLIBC_2.4 unlinkat F
>>>>  GLIBC_2.4 unshare F
>>>> +GLIBC_2.40 openat2 F
>>>>  GLIBC_2.5 __readlinkat_chk F
>>>>  GLIBC_2.5 inet6_opt_append F
>>>>  GLIBC_2.5 inet6_opt_find F
>>>> diff --git a/sysdeps/unix/sysv/linux/tst-openat2-consts.py b/sysdeps/unix/sysv/linux/tst-openat2-consts.py
>>>> new file mode 100755
>>>> index 0000000000..1623fafd94
>>>> --- /dev/null
>>>> +++ b/sysdeps/unix/sysv/linux/tst-openat2-consts.py
>>>> @@ -0,0 +1,63 @@
>>>> +#!/usr/bin/python3
>>>> +# Test that glibc's sys/openat2.h constants match the kernel's.
>>>> +# Copyright (C) 2024 Free Software Foundation, Inc.
>>>> +# This file is part of the GNU C Library.
>>>> +#
>>>> +# The GNU C Library is free software; you can redistribute it and/or
>>>> +# modify it under the terms of the GNU Lesser General Public
>>>> +# License as published by the Free Software Foundation; either
>>>> +# version 2.1 of the License, or (at your option) any later version.
>>>> +#
>>>> +# The GNU C Library is distributed in the hope that it will be useful,
>>>> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>>> +# Lesser General Public License for more details.
>>>> +#
>>>> +# You should have received a copy of the GNU Lesser General Public
>>>> +# License along with the GNU C Library; if not, see
>>>> +# <https://www.gnu.org/licenses/>.
>>>> +
>>>> +import argparse
>>>> +import sys
>>>> +
>>>> +import glibcextract
>>>> +import glibcsyscalls
>>>> +
>>>> +
>>>> +def main():
>>>> +    """The main entry point."""
>>>> +    parser = argparse.ArgumentParser(
>>>> +        description="Test that glibc's sys/openat2.h constants "
>>>> +        "match the kernel's.")
>>>> +    parser.add_argument('--cc', metavar='CC',
>>>> +                        help='C compiler (including options) to use')
>>>> +    args = parser.parse_args()
>>>> +
>>>> +    if glibcextract.compile_c_snippet(
>>>> +            '#include <linux/openat2.h>',
>>>> +            args.cc).returncode != 0:
>>>> +        sys.exit (77)
>>>> +
>>>> +    linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
>>>> +    # Constants in glibc were updated to match Linux v6.8.  When glibc
>>>> +    # constants are updated this value should be updated to match the
>>>> +    # released kernel version from which the constants were taken.
>>>> +    linux_version_glibc = (6, 8)
>>>> +    def check(cte, exclude=None):
>>>> +        return glibcextract.compare_macro_consts(
>>>> +                '#define _FCNTL_H\n'
>>>> +                '#include <stdint.h>\n'
>>>> +                '#include <bits/openat2.h>\n',
>>>> +                '#include <asm/fcntl.h>\n'
>>>> +                '#include <linux/openat2.h>\n',
>>>> +                args.cc,
>>>> +                cte,
>>>> +                exclude,
>>>> +                linux_version_glibc > linux_version_headers,
>>>> +                linux_version_headers > linux_version_glibc)
>>>> +
>>>> +    status = check('RESOLVE.*')
>>>> +    sys.exit(status)
>>>> +
>>>> +if __name__ == '__main__':
>>>> +    main()
>>>> diff --git a/sysdeps/unix/sysv/linux/tst-openat2.c b/sysdeps/unix/sysv/linux/tst-openat2.c
>>>> new file mode 100644
>>>> index 0000000000..d0c26f2bce
>>>> --- /dev/null
>>>> +++ b/sysdeps/unix/sysv/linux/tst-openat2.c
>>>> @@ -0,0 +1,259 @@
>>>> +/* Linux openat2 tests.
>>>> +   Copyright (C) 2024 Free Software Foundation, Inc.
>>>> +   This file is part of the GNU C Library.
>>>> +
>>>> +   The GNU C Library is free software; you can redistribute it and/or
>>>> +   modify it under the terms of the GNU Lesser General Public
>>>> +   License as published by the Free Software Foundation; either
>>>> +   version 2.1 of the License, or (at your option) any later version.
>>>> +
>>>> +   The GNU C Library is distributed in the hope that it will be useful,
>>>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>>> +   Lesser General Public License for more details.
>>>> +
>>>> +   You should have received a copy of the GNU Lesser General Public
>>>> +   License along with the GNU C Library; if not, see
>>>> +   <https://www.gnu.org/licenses/>.  */
>>>> +
>>>> +/* openat2 always return a file descriptor in LFS mode.  */
>>>> +#define _FILE_OFFSET_BITS 64
>>>> +
>>>> +#include <array_length.h>
>>>> +#include <errno.h>
>>>> +#include <fcntl.h>
>>>> +#include <stdint.h>
>>>> +#include <support/check.h>
>>>> +#include <support/temp_file.h>
>>>> +#include <support/xunistd.h>
>>>> +
>>>> +static int dir_fd;
>>>> +
>>>> +static void
>>>> +do_prepare (int argc, char *argv[])
>>>> +{
>>>> +  char *temp_dir = support_create_temp_directory ("tst-openat2");
>>>> +  dir_fd = xopen (temp_dir, O_RDONLY | O_DIRECTORY, 0);
>>>> +}
>>>> +#define PREPARE do_prepare
>>>> +
>>>> +static int
>>>> +do_test_struct (void)
>>>> +{
>>>> +  static struct struct_test
>>>> +  {
>>>> +    struct open_how_ext
>>>> +    {
>>>> +      struct open_how inner;
>>>> +      int extra1;
>>>> +      int extra2;
>>>> +      int extra3;
>>>> +    } arg;
>>>> +    size_t size;
>>>> +    int err;
>>>> +  } tests[] =
>>>> +  {
>>>> +    {
>>>> +      /* Zero size.  */
>>>> +      .arg.inner.flags = O_RDONLY,
>>>> +      .size = 0,
>>>> +      .err = EINVAL,
>>>> +    },
>>>> +    {
>>>> +      /* Normal struct.  */
>>>> +      .arg.inner.flags = O_RDONLY,
>>>> +      .size = sizeof (struct open_how),
>>>> +    },
>>>> +    {
>>>> +      /* Larger struct, zeroed out the unused values.  */
>>>> +      .arg.inner.flags = O_RDONLY,
>>>> +      .size = sizeof (struct open_how_ext),
>>>> +    },
>>>> +    {
>>>> +      /* Larger struct, non-zeroed out the unused values.  */
>>>> +      .arg.inner.flags = O_RDONLY,
>>>> +      .arg.extra1 = 0xdeadbeef,
>>>> +      .size = sizeof (struct open_how_ext),
>>>> +      .err = E2BIG,
>>>> +    },
>>>> +    {
>>>> +      /* Larger struct, non-zeroed out the unused values.  */
>>>> +      .arg.inner.flags = O_RDONLY,
>>>> +      .arg.extra2 = 0xdeadbeef,
>>>> +      .size = sizeof (struct open_how_ext),
>>>> +      .err = E2BIG,
>>>> +    },
>>>> +  };
>>>> +
>>>> +  for (struct struct_test *t = tests; t != array_end (tests); t++)
>>>> +    {
>>>> +      int fd = openat2 (AT_FDCWD, ".", (struct open_how *) &t->arg, t->size);
>>>> +      if (fd == -1 && errno == ENOSYS)
>>>> +       FAIL_UNSUPPORTED ("openat2 is not supported by the kernel");
>>>> +
>>>> +      if (t->err != 0)
>>>> +       {
>>>> +         TEST_COMPARE (fd, -1);
>>>> +         TEST_COMPARE (errno, t->err);
>>>> +       }
>>>> +      else
>>>> +       TEST_VERIFY (fd >= 0);
>>>> +    }
>>>> +
>>>> +  return 0;
>>>> +}
>>>> +
>>>> +static int
>>>> +do_test_flags (void)
>>>> +{
>>>> +  static struct flag_test
>>>> +  {
>>>> +    struct open_how how;
>>>> +    int err;
>>>> +  } tests[] =
>>>> +  {
>>>> +    /* O_TMPFILE is incompatible with O_PATH and O_CREAT.  */
>>>> +    { .how.flags = O_TMPFILE | O_PATH | O_RDWR, .err = EINVAL },
>>>> +    { .how.flags = O_TMPFILE | O_CREAT | O_RDWR, .err = EINVAL },
>>>> +
>>>> +    /* O_PATH only permits certain other flags to be set ...  */
>>>> +    { .how.flags = O_PATH | O_CLOEXEC },
>>>> +    { .how.flags = O_PATH | O_DIRECTORY },
>>>> +    { .how.flags = O_PATH | O_NOFOLLOW },
>>>> +    /* ... and others are absolutely not permitted. */
>>>> +    { .how.flags = O_PATH | O_RDWR, .err = EINVAL },
>>>> +    { .how.flags = O_PATH | O_CREAT, .err = EINVAL },
>>>> +    { .how.flags = O_PATH | O_EXCL, .err = EINVAL },
>>>> +    { .how.flags = O_PATH | O_NOCTTY, .err = EINVAL },
>>>> +    { .how.flags = O_PATH | O_DIRECT, .err = EINVAL },
>>>> +
>>>> +    /* ->mode must only be set with O_{CREAT,TMPFILE}. */
>>>> +    { .how.flags = O_RDONLY, .how.mode = 0600, .err = EINVAL },
>>>> +    { .how.flags = O_PATH,   .how.mode = 0600, .err = EINVAL },
>>>> +    { .how.flags = O_CREAT,  .how.mode = 0600 },
>>>> +    { .how.flags = O_TMPFILE | O_RDWR, .how.mode = 0600 },
>>>> +    /* ->mode must only contain 0777 bits. */
>>>> +    { .how.flags = O_CREAT, .how.mode = 0xFFFF, .err = EINVAL },
>>>> +    { .how.flags = O_CREAT, .how.mode = 0xC000000000000000ULL, .err = EINVAL },
>>>> +    { .how.flags = O_TMPFILE | O_RDWR, .how.mode = 0x1337, .err = EINVAL },
>>>> +    { .how.flags = O_TMPFILE | O_RDWR, .how.mode = 0x0000A00000000000ULL,
>>>> +      .err = EINVAL },
>>>> +
>>>> +    /* ->resolve flags must not conflict. */
>>>> +    { .how.flags = O_RDONLY,
>>>> +      .how.resolve = RESOLVE_BENEATH | RESOLVE_IN_ROOT,
>>>> +      .err = EINVAL },
>>>> +
>>>> +    /* ->resolve must only contain RESOLVE_* flags.  */
>>>> +    { .how.flags = O_RDONLY,
>>>> +      .how.resolve = 0x1337, .err = EINVAL },
>>>> +    { .how.flags = O_CREAT,
>>>> +      .how.resolve = 0x1337, .err = EINVAL },
>>>> +    { .how.flags = O_TMPFILE | O_RDWR,
>>>> +      .how.resolve = 0x1337, .err = EINVAL },
>>>> +    { .how.flags = O_PATH,
>>>> +      .how.resolve = 0x1337, .err = EINVAL },
>>>> +
>>>> +    /* currently unknown upper 32 bit rejected.  */
>>>> +    { .how.flags = O_RDONLY | (1ULL << 63),
>>>> +      .how.resolve = 0, .err = EINVAL },
>>>> +  };
>>>> +
>>>> +  for (struct flag_test *t = tests; t != array_end (tests); t++)
>>>> +    {
>>>> +      char *path;
>>>> +      if (t->how.flags & O_CREAT)
>>>> +       {
>>>> +         int temp_fd = create_temp_file ("tst-openat2.", &path);
>>>> +         TEST_VERIFY_EXIT (temp_fd != -1);
>>>> +         xunlink (path);
>>>> +       }
>>>> +      else
>>>> +       path = (char *) ".";
>>>> +
>>>> +      int fd = openat2 (AT_FDCWD, path, &t->how, sizeof (struct open_how));
>>>> +      if (fd != 0 && errno == EOPNOTSUPP)
>>>> +       {
>>>> +         /* Skip the testcase if FS does not support the operation (e.g.
>>>> +            valid O_TMPFILE on NFS).  */
>>>> +         continue;
>>>> +       }
>>>> +
>>>> +      if (t->err != 0)
>>>> +       {
>>>> +         TEST_COMPARE (fd, -1);
>>>> +         TEST_COMPARE (errno, t->err);
>>>> +       }
>>>> +      else
>>>> +       TEST_VERIFY (fd >= 0);
>>>> +    }
>>>> +
>>>> +  return 0;
>>>> +}
>>>> +
>>>> +static int
>>>> +do_test_basic (void)
>>>> +{
>>>> +  int fd;
>>>> +
>>>> +  fd = openat2 (dir_fd,
>>>> +               "some-file",
>>>> +               &(struct open_how)
>>>> +               {
>>>> +                 .flags = O_CREAT|O_RDWR|O_EXCL,
>>>> +                 .mode = 0666,
>>>> +               },
>>>> +               sizeof (struct open_how));
>>>> +  TEST_VERIFY (fd != -1);
>>>> +
>>>> +  xwrite (fd, "hello", 5);
>>>> +
>>>> +  /* Before closing the file, try using this file descriptor to open
>>>> +     another file.  This must fail.  */
>>>> +  {
>>>> +    int fd2 = openat2 (fd,
>>>> +                      "should-not-work",
>>>> +                      &(struct open_how)
>>>> +                      {
>>>> +                        .flags = O_CREAT|O_RDWR|O_EXCL,
>>>> +                        .mode = 0666,
>>>> +                      },
>>>> +                      sizeof (struct open_how));
>>>> +    TEST_COMPARE (fd2, -1);
>>>> +    TEST_COMPARE (errno, ENOTDIR);
>>>> +  }
>>>> +
>>>> +  /* Remove the created file.  */
>>>> +  int cwdfd = xopen (".", O_RDONLY | O_DIRECTORY, 0);
>>>> +  TEST_COMPARE (fchdir (dir_fd), 0);
>>>> +  xunlink ("some-file");
>>>> +  TEST_COMPARE (fchdir (cwdfd), 0);
>>>> +
>>>> +  xclose (dir_fd);
>>>> +  xclose (cwdfd);
>>>> +
>>>> +  fd = openat2 (dir_fd,
>>>> +               "some-file",
>>>> +               &(struct open_how)
>>>> +               {
>>>> +                 .flags = O_CREAT|O_RDWR|O_EXCL,
>>>> +                 .mode = 0666,
>>>> +               },
>>>> +               sizeof (struct open_how));
>>>> +  TEST_COMPARE (fd, -1);
>>>> +  TEST_COMPARE (errno, EBADF);
>>>> +
>>>> +  return 0;
>>>> +}
>>>> +
>>>> +static int
>>>> +do_test (void)
>>>> +{
>>>> +  do_test_struct ();
>>>> +  do_test_flags ();
>>>> +  do_test_basic ();
>>>> +
>>>> +  return 0;
>>>> +}
>>>> +
>>>> +#include <support/test-driver.c>
>>>> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
>>>> index aea7848ed6..a7f177c8a8 100644
>>>> --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
>>>> @@ -2744,6 +2744,7 @@ GLIBC_2.4 sys_errlist D 0x420
>>>>  GLIBC_2.4 sys_nerr D 0x4
>>>>  GLIBC_2.4 unlinkat F
>>>>  GLIBC_2.4 unshare F
>>>> +GLIBC_2.40 openat2 F
>>>>  GLIBC_2.5 __readlinkat_chk F
>>>>  GLIBC_2.5 inet6_opt_append F
>>>>  GLIBC_2.5 inet6_opt_find F
>>>> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
>>>> index 4ab3681914..00dfc8f1e7 100644
>>>> --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
>>>> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
>>>> @@ -2763,3 +2763,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
>>>>  GLIBC_2.39 stdc_trailing_zeros_ul F
>>>>  GLIBC_2.39 stdc_trailing_zeros_ull F
>>>>  GLIBC_2.39 stdc_trailing_zeros_us F
>>>> +GLIBC_2.40 openat2 F
>>>> --
>>>> 2.34.1
>>>>
enh April 25, 2024, 2:10 p.m. UTC | #5
On Thu, Apr 25, 2024 at 7:01 AM Adhemerval Zanella Netto
<adhemerval.zanella@linaro.org> wrote:
>
>
>
> On 24/04/24 18:18, enh wrote:
> > On Wed, Apr 24, 2024 at 11:05 AM Adhemerval Zanella Netto
> > <adhemerval.zanella@linaro.org> wrote:
> >>
> >> That's a good question, since we currently do not export any kernel interface
> >> which this new struct/size argument passing (we do use clone3, but it is
> >> just internally). For a libc/kernel interface, it should not matter; but from
> >> a libc exported symbol we indeed need to be more careful.
> >>
> >> From a glibc perpectiveI think we will need to *not* include kernel UAPI header,
> >> remove the size from the wrapper, and add some slack size on open_how for
> >> future extension.  It makes open_how extensions to not require new symbol
> >> version in the near future (similar to what was done for statx).
> >
> > i think statx did that _in uapi_, no? there's already padding
> > upstream. (that's a much better way to do these things from a libc
> > perspective; if someone talks to the kernel folks, it's worth trying
> > to encourage them to do more of that, and less of the openat2() or
> > sched_setattr().)
>
> Yes, the statx added some spare fields because it does not have the extra
> size parameter and an statx extension that extends further will require
> another syscall (this is the same for sched_setattr). The openat2 approach
> is not bad, it solves this issue.

it is bad, because it solves the _kernel_ problem by creating a
userspace problem.

(not versioning the _syscall_ is fine, as long as you version the
_struct_ -- and we have a void* and size_t in the libc api -- but not
versioning either just pushes new problems onto userspace. userspace
would be better off with multiple syscalls!)

> This new kernel interface also solves another other historical problem:
> it allows sizes larger than current supported as long extra fields are
> zeroed and returns EINVAL otherwise.  So I think is unlikely kernel will
> add spare field on open_how, it only ads extra complexity for the kABI.
>
> So for glibc I think it would still be better to add the spare fields,
> mainly to avoid the need to possible add new symbol versions if it requires
> to pick the struct for a eventual struct extension.
>
> >
> >> It would make the libc and kernel version not easily interchangeable (which
> >> some users do want on some cases).
> >>
> >> On 24/04/24 14:42, enh wrote:
> >>> doesn't glibc worry about types like this, where the size can change?
> >>> that presents a problem for code passing those types around. do you
> >>> require that all the code in a process be compiled with the exact same
> >>> headers?
> >>>
> >>> On Wed, Apr 24, 2024 at 10:38 AM Adhemerval Zanella
> >>> <adhemerval.zanella@linaro.org> wrote:
> >>>>
> >>>> It was added on Linux 5.6, as an extension of openat.  Different than
> >>>> other open-like functions, the kernel only provides the LFS variant (so
> >>>> files larger than 4GB always succeed, as other functions with offset
> >>>> larger than off_t).  Similar to other open functions, the new symbol is
> >>>> a cancellable entrypoint.
> >>>>
> >>>> The test case added only stresses some of the syscalls provided
> >>>> functionalities and it is based on an existent kernel self-test.  Since
> >>>> the prototype does not use variadic arguments, there is no need to add a
> >>>> fortify wrapper to catch wrong usages.
> >>>>
> >>>> Checked on x86_64-linux-gnu.
> >>>> ---
> >>>>  NEWS                                          |   4 +
> >>>>  sysdeps/unix/sysv/linux/Makefile              |  14 +
> >>>>  sysdeps/unix/sysv/linux/Versions              |   3 +
> >>>>  sysdeps/unix/sysv/linux/aarch64/libc.abilist  |   1 +
> >>>>  sysdeps/unix/sysv/linux/alpha/libc.abilist    |   1 +
> >>>>  sysdeps/unix/sysv/linux/arc/libc.abilist      |   1 +
> >>>>  sysdeps/unix/sysv/linux/arm/be/libc.abilist   |   1 +
> >>>>  sysdeps/unix/sysv/linux/arm/le/libc.abilist   |   1 +
> >>>>  sysdeps/unix/sysv/linux/bits/fcntl-linux.h    |  22 ++
> >>>>  sysdeps/unix/sysv/linux/bits/openat2.h        |  61 +++++
> >>>>  sysdeps/unix/sysv/linux/csky/libc.abilist     |   1 +
> >>>>  sysdeps/unix/sysv/linux/hppa/libc.abilist     |   1 +
> >>>>  sysdeps/unix/sysv/linux/i386/libc.abilist     |   1 +
> >>>>  .../sysv/linux/loongarch/lp64/libc.abilist    |   1 +
> >>>>  .../sysv/linux/m68k/coldfire/libc.abilist     |   1 +
> >>>>  .../unix/sysv/linux/m68k/m680x0/libc.abilist  |   1 +
> >>>>  .../sysv/linux/microblaze/be/libc.abilist     |   1 +
> >>>>  .../sysv/linux/microblaze/le/libc.abilist     |   1 +
> >>>>  .../sysv/linux/mips/mips32/fpu/libc.abilist   |   1 +
> >>>>  .../sysv/linux/mips/mips32/nofpu/libc.abilist |   1 +
> >>>>  .../sysv/linux/mips/mips64/n32/libc.abilist   |   1 +
> >>>>  .../sysv/linux/mips/mips64/n64/libc.abilist   |   1 +
> >>>>  sysdeps/unix/sysv/linux/nios2/libc.abilist    |   1 +
> >>>>  sysdeps/unix/sysv/linux/openat2.c             |  29 ++
> >>>>  sysdeps/unix/sysv/linux/or1k/libc.abilist     |   1 +
> >>>>  .../linux/powerpc/powerpc32/fpu/libc.abilist  |   1 +
> >>>>  .../powerpc/powerpc32/nofpu/libc.abilist      |   1 +
> >>>>  .../linux/powerpc/powerpc64/be/libc.abilist   |   1 +
> >>>>  .../linux/powerpc/powerpc64/le/libc.abilist   |   1 +
> >>>>  .../unix/sysv/linux/riscv/rv32/libc.abilist   |   1 +
> >>>>  .../unix/sysv/linux/riscv/rv64/libc.abilist   |   1 +
> >>>>  .../unix/sysv/linux/s390/s390-32/libc.abilist |   1 +
> >>>>  .../unix/sysv/linux/s390/s390-64/libc.abilist |   1 +
> >>>>  sysdeps/unix/sysv/linux/sh/be/libc.abilist    |   1 +
> >>>>  sysdeps/unix/sysv/linux/sh/le/libc.abilist    |   1 +
> >>>>  .../sysv/linux/sparc/sparc32/libc.abilist     |   1 +
> >>>>  .../sysv/linux/sparc/sparc64/libc.abilist     |   1 +
> >>>>  sysdeps/unix/sysv/linux/tst-openat2-consts.py |  63 +++++
> >>>>  sysdeps/unix/sysv/linux/tst-openat2.c         | 259 ++++++++++++++++++
> >>>>  .../unix/sysv/linux/x86_64/64/libc.abilist    |   1 +
> >>>>  .../unix/sysv/linux/x86_64/x32/libc.abilist   |   1 +
> >>>>  41 files changed, 488 insertions(+)
> >>>>  create mode 100644 sysdeps/unix/sysv/linux/bits/openat2.h
> >>>>  create mode 100644 sysdeps/unix/sysv/linux/openat2.c
> >>>>  create mode 100755 sysdeps/unix/sysv/linux/tst-openat2-consts.py
> >>>>  create mode 100644 sysdeps/unix/sysv/linux/tst-openat2.c
> >>>>
> >>>> diff --git a/NEWS b/NEWS
> >>>> index cf6078cf20..eaaa02cb4e 100644
> >>>> --- a/NEWS
> >>>> +++ b/NEWS
> >>>> @@ -26,6 +26,10 @@ Major new features:
> >>>>    more extensive verification tests for AT_SECURE programs and not meant to
> >>>>    be a security feature.
> >>>>
> >>>> +* On Linux, the openat2 function has been added.  It is an extension of
> >>>> +  openat and provides a superset of its functionality.  It is supported only
> >>>> +  in LFS mode and as other open like it is a cancellable entrypoint.
> >>>> +
> >>>>  Deprecated and removed features, and other changes affecting compatibility:
> >>>>
> >>>>  * Architectures which use a 32-bit seconds-since-epoch field in struct
> >>>> diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
> >>>> index 415aa1f14d..4ae8ec6dc6 100644
> >>>> --- a/sysdeps/unix/sysv/linux/Makefile
> >>>> +++ b/sysdeps/unix/sysv/linux/Makefile
> >>>> @@ -133,6 +133,7 @@ sysdep_headers += \
> >>>>    bits/mman-linux.h \
> >>>>    bits/mman-map-flags-generic.h \
> >>>>    bits/mman-shared.h \
> >>>> +  bits/openat2.h \
> >>>>    bits/procfs-extra.h \
> >>>>    bits/procfs-id.h \
> >>>>    bits/procfs-prregset.h \
> >>>> @@ -591,6 +592,7 @@ sysdep_routines += \
> >>>>    internal_statvfs \
> >>>>    open64_nocancel \
> >>>>    open_nocancel \
> >>>> +  openat2 \
> >>>>    openat64_nocancel \
> >>>>    openat_nocancel \
> >>>>    pread64_nocancel \
> >>>> @@ -611,7 +613,19 @@ tests += \
> >>>>    tst-fallocate64 \
> >>>>    tst-getcwd-smallbuff \
> >>>>    tst-o_path-locks \
> >>>> +  tst-openat2 \
> >>>>    # tests
> >>>> +
> >>>> +tests-special += \
> >>>> +  $(objpfx)tst-openat2-consts.out \
> >>>> +  # tests-special
> >>>> +$(objpfx)tst-openat2-consts.out: ../sysdeps/unix/sysv/linux/tst-openat2-consts.py
> >>>> +       $(sysdeps-linux-python) \
> >>>> +         ../sysdeps/unix/sysv/linux/tst-openat2-consts.py \
> >>>> +           $(sysdeps-linux-python-cc) \
> >>>> +         < /dev/null > $@ 2>&1; $(evaluate-test)
> >>>> +$(objpfx)tst-openat2-consts.out: $(sysdeps-linux-python-deps)
> >>>> +
> >>>>  endif
> >>>>
> >>>>  ifeq ($(subdir),elf)
> >>>> diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions
> >>>> index 268ba1b6ac..65da2b617a 100644
> >>>> --- a/sysdeps/unix/sysv/linux/Versions
> >>>> +++ b/sysdeps/unix/sysv/linux/Versions
> >>>> @@ -328,6 +328,9 @@ libc {
> >>>>      posix_spawnattr_getcgroup_np;
> >>>>      posix_spawnattr_setcgroup_np;
> >>>>    }
> >>>> +  GLIBC_2.40 {
> >>>> +    openat2;
> >>>> +  }
> >>>>    GLIBC_PRIVATE {
> >>>>      # functions used in other libraries
> >>>>      __syscall_rt_sigqueueinfo;
> >>>> diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> >>>> index 68eeca1c08..0b9bd8ae62 100644
> >>>> --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> >>>> @@ -2748,3 +2748,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_ul F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_ull F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_us F
> >>>> +GLIBC_2.40 openat2 F
> >>>> diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> >>>> index 34c187b721..c0bd27d617 100644
> >>>> --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> >>>> @@ -3095,6 +3095,7 @@ GLIBC_2.4 wcstold F
> >>>>  GLIBC_2.4 wcstold_l F
> >>>>  GLIBC_2.4 wprintf F
> >>>>  GLIBC_2.4 wscanf F
> >>>> +GLIBC_2.40 openat2 F
> >>>>  GLIBC_2.5 __readlinkat_chk F
> >>>>  GLIBC_2.5 inet6_opt_append F
> >>>>  GLIBC_2.5 inet6_opt_find F
> >>>> diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
> >>>> index 916c18ea94..965438e7a7 100644
> >>>> --- a/sysdeps/unix/sysv/linux/arc/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
> >>>> @@ -2509,3 +2509,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_ul F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_ull F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_us F
> >>>> +GLIBC_2.40 openat2 F
> >>>> diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> >>>> index ea95de282a..e69ed8c903 100644
> >>>> --- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> >>>> @@ -2801,6 +2801,7 @@ GLIBC_2.4 xdrstdio_create F
> >>>>  GLIBC_2.4 xencrypt F
> >>>>  GLIBC_2.4 xprt_register F
> >>>>  GLIBC_2.4 xprt_unregister F
> >>>> +GLIBC_2.40 openat2 F
> >>>>  GLIBC_2.5 __readlinkat_chk F
> >>>>  GLIBC_2.5 inet6_opt_append F
> >>>>  GLIBC_2.5 inet6_opt_find F
> >>>> diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> >>>> index 1cdbc983e1..70fd425869 100644
> >>>> --- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> >>>> @@ -2798,6 +2798,7 @@ GLIBC_2.4 xdrstdio_create F
> >>>>  GLIBC_2.4 xencrypt F
> >>>>  GLIBC_2.4 xprt_register F
> >>>>  GLIBC_2.4 xprt_unregister F
> >>>> +GLIBC_2.40 openat2 F
> >>>>  GLIBC_2.5 __readlinkat_chk F
> >>>>  GLIBC_2.5 inet6_opt_append F
> >>>>  GLIBC_2.5 inet6_opt_find F
> >>>> diff --git a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
> >>>> index 628612b885..279aa2b8eb 100644
> >>>> --- a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
> >>>> +++ b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
> >>>> @@ -451,6 +451,28 @@ extern int name_to_handle_at (int __dfd, const char *__name,
> >>>>  extern int open_by_handle_at (int __mountdirfd, struct file_handle *__handle,
> >>>>                               int __flags);
> >>>>
> >>>> +#ifdef __has_include
> >>>> +# if __has_include ("linux/openat2.h")
> >>>> +#  include "linux/openat2.h"
> >>>> +#  define __glibc_has_open_how 1
> >>>> +# endif
> >>>> +#endif
> >>>> +
> >>>> +#include <bits/openat2.h>
> >>>> +
> >>>> +/* Similar to `openat' but the arguments are packed on HOW with the size
> >>>> +   USIZE.  If flags and mode from HOW are non-zero, then openat2 operates
> >>>> +   like openat.
> >>>> +
> >>>> +   Unlike openat2, unknown or invalid flags result in an error (EINVAL),
> >>>> +   rather than being ignored.  The mode must be zero unless one O_CREAT
> >>>> +   or O_TMPFILE are set.
> >>>> +
> >>>> +   The kernel does not support legacy non-LFS interface.  */
> >>>> +extern int openat2 (int __dfd, const char *__filename, struct open_how *__how,
> >>>> +                   size_t __usize)
> >>>> +     __nonnull ((2, 3));
> >>>> +
> >>>>  #endif /* use GNU */
> >>>>
> >>>>  __END_DECLS
> >>>> diff --git a/sysdeps/unix/sysv/linux/bits/openat2.h b/sysdeps/unix/sysv/linux/bits/openat2.h
> >>>> new file mode 100644
> >>>> index 0000000000..a07984dace
> >>>> --- /dev/null
> >>>> +++ b/sysdeps/unix/sysv/linux/bits/openat2.h
> >>>> @@ -0,0 +1,61 @@
> >>>> +/* openat2 definition.  Linux specific.
> >>>> +   Copyright (C) 2024 Free Software Foundation, Inc.
> >>>> +   This file is part of the GNU C Library.
> >>>> +
> >>>> +   The GNU C Library is free software; you can redistribute it and/or
> >>>> +   modify it under the terms of the GNU Lesser General Public
> >>>> +   License as published by the Free Software Foundation; either
> >>>> +   version 2.1 of the License, or (at your option) any later version.
> >>>> +
> >>>> +   The GNU C Library is distributed in the hope that it will be useful,
> >>>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> >>>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> >>>> +   Lesser General Public License for more details.
> >>>> +
> >>>> +   You should have received a copy of the GNU Lesser General Public
> >>>> +   License along with the GNU C Library; if not, see
> >>>> +   <https://www.gnu.org/licenses/>.  */
> >>>> +
> >>>> +#ifndef        _FCNTL_H
> >>>> +# error "Never use <bits/openat2.h> directly; include <fcntl.h> instead."
> >>>> +#endif
> >>>> +
> >>>> +#ifndef __glibc_has_open_how
> >>>> +/* Arguments for how openat2 should open the target path.  */
> >>>> +struct open_how
> >>>> +{
> >>>> +  __uint64_t flags;
> >>>> +  __uint64_t mode;
> >>>> +  __uint64_t resolve;
> >>>> +};
> >>>> +#endif
> >>>> +
> >>>> +/* how->resolve flags for openat2. */
> >>>> +#ifndef RESOLVE_NO_XDEV
> >>>> +# define RESOLVE_NO_XDEV       0x01 /* Block mount-point crossings
> >>>> +                                       (includes bind-mounts).  */
> >>>> +#endif
> >>>> +#ifndef RESOLVE_NO_MAGICLINKS
> >>>> +# define RESOLVE_NO_MAGICLINKS 0x02 /* Block traversal through procfs-style
> >>>> +                                       "magic-links".  */
> >>>> +#endif
> >>>> +#ifndef RESOLVE_NO_SYMLINKS
> >>>> +# define RESOLVE_NO_SYMLINKS   0x04 /* Block traversal through all symlinks
> >>>> +                                       (implies OEXT_NO_MAGICLINKS).  */
> >>>> +#endif
> >>>> +#ifndef RESOLVE_BENEATH
> >>>> +# define RESOLVE_BENEATH       0x08 /* Block "lexical" trickery like
> >>>> +                                       "..", symlinks, and absolute
> >>>> +                                       paths which escape the dirfd.  */
> >>>> +#endif
> >>>> +#ifndef RESOLVE_IN_ROOT
> >>>> +# define RESOLVE_IN_ROOT       0x10 /* Make all jumps to "/" and ".."
> >>>> +                                       be scoped inside the dirfd
> >>>> +                                       (similar to chroot).  */
> >>>> +#endif
> >>>> +#ifndef RESOLVE_CACHED
> >>>> +# define RESOLVE_CACHED                0x20 /* Only complete if resolution can be
> >>>> +                                       completed through cached lookup. May
> >>>> +                                       return -EAGAIN if that's not
> >>>> +                                       possible.  */
> >>>> +#endif
> >>>> diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
> >>>> index 96d45961e2..c81ea43dc1 100644
> >>>> --- a/sysdeps/unix/sysv/linux/csky/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
> >>>> @@ -2785,3 +2785,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_ul F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_ull F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_us F
> >>>> +GLIBC_2.40 openat2 F
> >>>> diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> >>>> index fbcd60c2b3..23eec25d8a 100644
> >>>> --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> >>>> @@ -2821,6 +2821,7 @@ GLIBC_2.4 sys_errlist D 0x400
> >>>>  GLIBC_2.4 sys_nerr D 0x4
> >>>>  GLIBC_2.4 unlinkat F
> >>>>  GLIBC_2.4 unshare F
> >>>> +GLIBC_2.40 openat2 F
> >>>>  GLIBC_2.5 __readlinkat_chk F
> >>>>  GLIBC_2.5 inet6_opt_append F
> >>>>  GLIBC_2.5 inet6_opt_find F
> >>>> diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
> >>>> index c989b433c0..4ce2afb147 100644
> >>>> --- a/sysdeps/unix/sysv/linux/i386/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
> >>>> @@ -3005,6 +3005,7 @@ GLIBC_2.4 sys_errlist D 0x210
> >>>>  GLIBC_2.4 sys_nerr D 0x4
> >>>>  GLIBC_2.4 unlinkat F
> >>>>  GLIBC_2.4 unshare F
> >>>> +GLIBC_2.40 openat2 F
> >>>>  GLIBC_2.5 __readlinkat_chk F
> >>>>  GLIBC_2.5 inet6_opt_append F
> >>>>  GLIBC_2.5 inet6_opt_find F
> >>>> diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
> >>>> index 0023ec1fa1..be76251b28 100644
> >>>> --- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
> >>>> @@ -2269,3 +2269,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_ul F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_ull F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_us F
> >>>> +GLIBC_2.40 openat2 F
> >>>> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> >>>> index d9bd6a9b56..5ff3db5035 100644
> >>>> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> >>>> @@ -2781,6 +2781,7 @@ GLIBC_2.4 xdrstdio_create F
> >>>>  GLIBC_2.4 xencrypt F
> >>>>  GLIBC_2.4 xprt_register F
> >>>>  GLIBC_2.4 xprt_unregister F
> >>>> +GLIBC_2.40 openat2 F
> >>>>  GLIBC_2.5 __readlinkat_chk F
> >>>>  GLIBC_2.5 inet6_opt_append F
> >>>>  GLIBC_2.5 inet6_opt_find F
> >>>> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> >>>> index 439796d693..39645248af 100644
> >>>> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> >>>> @@ -2948,6 +2948,7 @@ GLIBC_2.4 sys_errlist D 0x210
> >>>>  GLIBC_2.4 sys_nerr D 0x4
> >>>>  GLIBC_2.4 unlinkat F
> >>>>  GLIBC_2.4 unshare F
> >>>> +GLIBC_2.40 openat2 F
> >>>>  GLIBC_2.5 __readlinkat_chk F
> >>>>  GLIBC_2.5 inet6_opt_append F
> >>>>  GLIBC_2.5 inet6_opt_find F
> >>>> diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> >>>> index 1069d3252c..2f917724de 100644
> >>>> --- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> >>>> @@ -2834,3 +2834,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_ul F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_ull F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_us F
> >>>> +GLIBC_2.40 openat2 F
> >>>> diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> >>>> index 17abe08c8b..6cc64f97b5 100644
> >>>> --- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> >>>> @@ -2831,3 +2831,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_ul F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_ull F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_us F
> >>>> +GLIBC_2.40 openat2 F
> >>>> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> >>>> index 799e508950..ae5b95bc76 100644
> >>>> --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> >>>> @@ -2909,6 +2909,7 @@ GLIBC_2.4 renameat F
> >>>>  GLIBC_2.4 symlinkat F
> >>>>  GLIBC_2.4 unlinkat F
> >>>>  GLIBC_2.4 unshare F
> >>>> +GLIBC_2.40 openat2 F
> >>>>  GLIBC_2.5 __readlinkat_chk F
> >>>>  GLIBC_2.5 inet6_opt_append F
> >>>>  GLIBC_2.5 inet6_opt_find F
> >>>> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> >>>> index 1c10996cbc..434e997937 100644
> >>>> --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> >>>> @@ -2907,6 +2907,7 @@ GLIBC_2.4 renameat F
> >>>>  GLIBC_2.4 symlinkat F
> >>>>  GLIBC_2.4 unlinkat F
> >>>>  GLIBC_2.4 unshare F
> >>>> +GLIBC_2.40 openat2 F
> >>>>  GLIBC_2.5 __readlinkat_chk F
> >>>>  GLIBC_2.5 inet6_opt_append F
> >>>>  GLIBC_2.5 inet6_opt_find F
> >>>> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> >>>> index 03d9655f26..5dc2996fcc 100644
> >>>> --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> >>>> @@ -2915,6 +2915,7 @@ GLIBC_2.4 renameat F
> >>>>  GLIBC_2.4 symlinkat F
> >>>>  GLIBC_2.4 unlinkat F
> >>>>  GLIBC_2.4 unshare F
> >>>> +GLIBC_2.40 openat2 F
> >>>>  GLIBC_2.5 __readlinkat_chk F
> >>>>  GLIBC_2.5 inet6_opt_append F
> >>>>  GLIBC_2.5 inet6_opt_find F
> >>>> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> >>>> index 05e402ed30..865dc5e7f1 100644
> >>>> --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> >>>> @@ -2817,6 +2817,7 @@ GLIBC_2.4 renameat F
> >>>>  GLIBC_2.4 symlinkat F
> >>>>  GLIBC_2.4 unlinkat F
> >>>>  GLIBC_2.4 unshare F
> >>>> +GLIBC_2.40 openat2 F
> >>>>  GLIBC_2.5 __readlinkat_chk F
> >>>>  GLIBC_2.5 inet6_opt_append F
> >>>>  GLIBC_2.5 inet6_opt_find F
> >>>> diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> >>>> index 3aa81766aa..12775fdad5 100644
> >>>> --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> >>>> @@ -2873,3 +2873,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_ul F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_ull F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_us F
> >>>> +GLIBC_2.40 openat2 F
> >>>> diff --git a/sysdeps/unix/sysv/linux/openat2.c b/sysdeps/unix/sysv/linux/openat2.c
> >>>> new file mode 100644
> >>>> index 0000000000..a2b134bab0
> >>>> --- /dev/null
> >>>> +++ b/sysdeps/unix/sysv/linux/openat2.c
> >>>> @@ -0,0 +1,29 @@
> >>>> +/* Linux openat2 syscall implementation.
> >>>> +   Copyright (C) 2024 Free Software Foundation, Inc.
> >>>> +   This file is part of the GNU C Library.
> >>>> +
> >>>> +   The GNU C Library is free software; you can redistribute it and/or
> >>>> +   modify it under the terms of the GNU Lesser General Public
> >>>> +   License as published by the Free Software Foundation; either
> >>>> +   version 2.1 of the License, or (at your option) any later version.
> >>>> +
> >>>> +   The GNU C Library is distributed in the hope that it will be useful,
> >>>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> >>>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> >>>> +   Lesser General Public License for more details.
> >>>> +
> >>>> +   You should have received a copy of the GNU Lesser General Public
> >>>> +   License along with the GNU C Library; if not, see
> >>>> +   <https://www.gnu.org/licenses/>.  */
> >>>> +
> >>>> +#include <fcntl.h>
> >>>> +#include <bits/openat2.h>
> >>>> +#include <sysdep-cancel.h>
> >>>> +
> >>>> +int
> >>>> +__openat2 (int dfd, const char *filename, struct open_how *how,
> >>>> +          size_t usize)
> >>>> +{
> >>>> +  return SYSCALL_CANCEL (openat2, dfd, filename, how, usize);
> >>>> +}
> >>>> +weak_alias (__openat2, openat2)
> >>>> diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist
> >>>> index c40c843aaf..2835436011 100644
> >>>> --- a/sysdeps/unix/sysv/linux/or1k/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist
> >>>> @@ -2255,3 +2255,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_ul F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_ull F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_us F
> >>>> +GLIBC_2.40 openat2 F
> >>>> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> >>>> index 9714305608..3b70a56944 100644
> >>>> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> >>>> @@ -3138,6 +3138,7 @@ GLIBC_2.4 wcstold F
> >>>>  GLIBC_2.4 wcstold_l F
> >>>>  GLIBC_2.4 wprintf F
> >>>>  GLIBC_2.4 wscanf F
> >>>> +GLIBC_2.40 openat2 F
> >>>>  GLIBC_2.5 __readlinkat_chk F
> >>>>  GLIBC_2.5 inet6_opt_append F
> >>>>  GLIBC_2.5 inet6_opt_find F
> >>>> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> >>>> index 0beb52c542..677c9a75de 100644
> >>>> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> >>>> @@ -3183,6 +3183,7 @@ GLIBC_2.4 wcstold F
> >>>>  GLIBC_2.4 wcstold_l F
> >>>>  GLIBC_2.4 wprintf F
> >>>>  GLIBC_2.4 wscanf F
> >>>> +GLIBC_2.40 openat2 F
> >>>>  GLIBC_2.5 __readlinkat_chk F
> >>>>  GLIBC_2.5 inet6_opt_append F
> >>>>  GLIBC_2.5 inet6_opt_find F
> >>>> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> >>>> index cfc2ebd3ec..10fc3c89dc 100644
> >>>> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> >>>> @@ -2892,6 +2892,7 @@ GLIBC_2.4 wcstold F
> >>>>  GLIBC_2.4 wcstold_l F
> >>>>  GLIBC_2.4 wprintf F
> >>>>  GLIBC_2.4 wscanf F
> >>>> +GLIBC_2.40 openat2 F
> >>>>  GLIBC_2.5 __readlinkat_chk F
> >>>>  GLIBC_2.5 inet6_opt_append F
> >>>>  GLIBC_2.5 inet6_opt_find F
> >>>> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> >>>> index 8c9efc5a16..713fa1d1c8 100644
> >>>> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> >>>> @@ -2968,3 +2968,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_ul F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_ull F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_us F
> >>>> +GLIBC_2.40 openat2 F
> >>>> diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> >>>> index 6397a9cb91..550ba877ef 100644
> >>>> --- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> >>>> @@ -2512,3 +2512,4 @@ GLIBC_2.39 stdc_trailing_zeros_ul F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_ull F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_us F
> >>>>  GLIBC_2.40 __riscv_hwprobe F
> >>>> +GLIBC_2.40 openat2 F
> >>>> diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> >>>> index 71bbf94f66..8bf9f309b7 100644
> >>>> --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> >>>> @@ -2712,3 +2712,4 @@ GLIBC_2.39 stdc_trailing_zeros_ul F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_ull F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_us F
> >>>>  GLIBC_2.40 __riscv_hwprobe F
> >>>> +GLIBC_2.40 openat2 F
> >>>> diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> >>>> index a7467e2850..08bc3d6f8b 100644
> >>>> --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> >>>> @@ -3136,6 +3136,7 @@ GLIBC_2.4 wcstold F
> >>>>  GLIBC_2.4 wcstold_l F
> >>>>  GLIBC_2.4 wprintf F
> >>>>  GLIBC_2.4 wscanf F
> >>>> +GLIBC_2.40 openat2 F
> >>>>  GLIBC_2.5 __readlinkat_chk F
> >>>>  GLIBC_2.5 inet6_opt_append F
> >>>>  GLIBC_2.5 inet6_opt_find F
> >>>> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> >>>> index fd1cb2972d..e25afff581 100644
> >>>> --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> >>>> @@ -2929,6 +2929,7 @@ GLIBC_2.4 wcstold F
> >>>>  GLIBC_2.4 wcstold_l F
> >>>>  GLIBC_2.4 wprintf F
> >>>>  GLIBC_2.4 wscanf F
> >>>> +GLIBC_2.40 openat2 F
> >>>>  GLIBC_2.5 __readlinkat_chk F
> >>>>  GLIBC_2.5 inet6_opt_append F
> >>>>  GLIBC_2.5 inet6_opt_find F
> >>>> diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> >>>> index ff6e6b1a13..499de50ee0 100644
> >>>> --- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> >>>> @@ -2828,6 +2828,7 @@ GLIBC_2.4 sys_errlist D 0x210
> >>>>  GLIBC_2.4 sys_nerr D 0x4
> >>>>  GLIBC_2.4 unlinkat F
> >>>>  GLIBC_2.4 unshare F
> >>>> +GLIBC_2.40 openat2 F
> >>>>  GLIBC_2.5 __readlinkat_chk F
> >>>>  GLIBC_2.5 inet6_opt_append F
> >>>>  GLIBC_2.5 inet6_opt_find F
> >>>> diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> >>>> index 449d92bbc5..bdd9c600f0 100644
> >>>> --- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> >>>> @@ -2825,6 +2825,7 @@ GLIBC_2.4 sys_errlist D 0x210
> >>>>  GLIBC_2.4 sys_nerr D 0x4
> >>>>  GLIBC_2.4 unlinkat F
> >>>>  GLIBC_2.4 unshare F
> >>>> +GLIBC_2.40 openat2 F
> >>>>  GLIBC_2.5 __readlinkat_chk F
> >>>>  GLIBC_2.5 inet6_opt_append F
> >>>>  GLIBC_2.5 inet6_opt_find F
> >>>> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> >>>> index e615be759a..b20dd43d47 100644
> >>>> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> >>>> @@ -3157,6 +3157,7 @@ GLIBC_2.4 wcstold F
> >>>>  GLIBC_2.4 wcstold_l F
> >>>>  GLIBC_2.4 wprintf F
> >>>>  GLIBC_2.4 wscanf F
> >>>> +GLIBC_2.40 openat2 F
> >>>>  GLIBC_2.5 __readlinkat_chk F
> >>>>  GLIBC_2.5 inet6_opt_append F
> >>>>  GLIBC_2.5 inet6_opt_find F
> >>>> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> >>>> index bd36431dd7..19981aa981 100644
> >>>> --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> >>>> @@ -2793,6 +2793,7 @@ GLIBC_2.4 sys_errlist D 0x430
> >>>>  GLIBC_2.4 sys_nerr D 0x4
> >>>>  GLIBC_2.4 unlinkat F
> >>>>  GLIBC_2.4 unshare F
> >>>> +GLIBC_2.40 openat2 F
> >>>>  GLIBC_2.5 __readlinkat_chk F
> >>>>  GLIBC_2.5 inet6_opt_append F
> >>>>  GLIBC_2.5 inet6_opt_find F
> >>>> diff --git a/sysdeps/unix/sysv/linux/tst-openat2-consts.py b/sysdeps/unix/sysv/linux/tst-openat2-consts.py
> >>>> new file mode 100755
> >>>> index 0000000000..1623fafd94
> >>>> --- /dev/null
> >>>> +++ b/sysdeps/unix/sysv/linux/tst-openat2-consts.py
> >>>> @@ -0,0 +1,63 @@
> >>>> +#!/usr/bin/python3
> >>>> +# Test that glibc's sys/openat2.h constants match the kernel's.
> >>>> +# Copyright (C) 2024 Free Software Foundation, Inc.
> >>>> +# This file is part of the GNU C Library.
> >>>> +#
> >>>> +# The GNU C Library is free software; you can redistribute it and/or
> >>>> +# modify it under the terms of the GNU Lesser General Public
> >>>> +# License as published by the Free Software Foundation; either
> >>>> +# version 2.1 of the License, or (at your option) any later version.
> >>>> +#
> >>>> +# The GNU C Library is distributed in the hope that it will be useful,
> >>>> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> >>>> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> >>>> +# Lesser General Public License for more details.
> >>>> +#
> >>>> +# You should have received a copy of the GNU Lesser General Public
> >>>> +# License along with the GNU C Library; if not, see
> >>>> +# <https://www.gnu.org/licenses/>.
> >>>> +
> >>>> +import argparse
> >>>> +import sys
> >>>> +
> >>>> +import glibcextract
> >>>> +import glibcsyscalls
> >>>> +
> >>>> +
> >>>> +def main():
> >>>> +    """The main entry point."""
> >>>> +    parser = argparse.ArgumentParser(
> >>>> +        description="Test that glibc's sys/openat2.h constants "
> >>>> +        "match the kernel's.")
> >>>> +    parser.add_argument('--cc', metavar='CC',
> >>>> +                        help='C compiler (including options) to use')
> >>>> +    args = parser.parse_args()
> >>>> +
> >>>> +    if glibcextract.compile_c_snippet(
> >>>> +            '#include <linux/openat2.h>',
> >>>> +            args.cc).returncode != 0:
> >>>> +        sys.exit (77)
> >>>> +
> >>>> +    linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
> >>>> +    # Constants in glibc were updated to match Linux v6.8.  When glibc
> >>>> +    # constants are updated this value should be updated to match the
> >>>> +    # released kernel version from which the constants were taken.
> >>>> +    linux_version_glibc = (6, 8)
> >>>> +    def check(cte, exclude=None):
> >>>> +        return glibcextract.compare_macro_consts(
> >>>> +                '#define _FCNTL_H\n'
> >>>> +                '#include <stdint.h>\n'
> >>>> +                '#include <bits/openat2.h>\n',
> >>>> +                '#include <asm/fcntl.h>\n'
> >>>> +                '#include <linux/openat2.h>\n',
> >>>> +                args.cc,
> >>>> +                cte,
> >>>> +                exclude,
> >>>> +                linux_version_glibc > linux_version_headers,
> >>>> +                linux_version_headers > linux_version_glibc)
> >>>> +
> >>>> +    status = check('RESOLVE.*')
> >>>> +    sys.exit(status)
> >>>> +
> >>>> +if __name__ == '__main__':
> >>>> +    main()
> >>>> diff --git a/sysdeps/unix/sysv/linux/tst-openat2.c b/sysdeps/unix/sysv/linux/tst-openat2.c
> >>>> new file mode 100644
> >>>> index 0000000000..d0c26f2bce
> >>>> --- /dev/null
> >>>> +++ b/sysdeps/unix/sysv/linux/tst-openat2.c
> >>>> @@ -0,0 +1,259 @@
> >>>> +/* Linux openat2 tests.
> >>>> +   Copyright (C) 2024 Free Software Foundation, Inc.
> >>>> +   This file is part of the GNU C Library.
> >>>> +
> >>>> +   The GNU C Library is free software; you can redistribute it and/or
> >>>> +   modify it under the terms of the GNU Lesser General Public
> >>>> +   License as published by the Free Software Foundation; either
> >>>> +   version 2.1 of the License, or (at your option) any later version.
> >>>> +
> >>>> +   The GNU C Library is distributed in the hope that it will be useful,
> >>>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> >>>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> >>>> +   Lesser General Public License for more details.
> >>>> +
> >>>> +   You should have received a copy of the GNU Lesser General Public
> >>>> +   License along with the GNU C Library; if not, see
> >>>> +   <https://www.gnu.org/licenses/>.  */
> >>>> +
> >>>> +/* openat2 always return a file descriptor in LFS mode.  */
> >>>> +#define _FILE_OFFSET_BITS 64
> >>>> +
> >>>> +#include <array_length.h>
> >>>> +#include <errno.h>
> >>>> +#include <fcntl.h>
> >>>> +#include <stdint.h>
> >>>> +#include <support/check.h>
> >>>> +#include <support/temp_file.h>
> >>>> +#include <support/xunistd.h>
> >>>> +
> >>>> +static int dir_fd;
> >>>> +
> >>>> +static void
> >>>> +do_prepare (int argc, char *argv[])
> >>>> +{
> >>>> +  char *temp_dir = support_create_temp_directory ("tst-openat2");
> >>>> +  dir_fd = xopen (temp_dir, O_RDONLY | O_DIRECTORY, 0);
> >>>> +}
> >>>> +#define PREPARE do_prepare
> >>>> +
> >>>> +static int
> >>>> +do_test_struct (void)
> >>>> +{
> >>>> +  static struct struct_test
> >>>> +  {
> >>>> +    struct open_how_ext
> >>>> +    {
> >>>> +      struct open_how inner;
> >>>> +      int extra1;
> >>>> +      int extra2;
> >>>> +      int extra3;
> >>>> +    } arg;
> >>>> +    size_t size;
> >>>> +    int err;
> >>>> +  } tests[] =
> >>>> +  {
> >>>> +    {
> >>>> +      /* Zero size.  */
> >>>> +      .arg.inner.flags = O_RDONLY,
> >>>> +      .size = 0,
> >>>> +      .err = EINVAL,
> >>>> +    },
> >>>> +    {
> >>>> +      /* Normal struct.  */
> >>>> +      .arg.inner.flags = O_RDONLY,
> >>>> +      .size = sizeof (struct open_how),
> >>>> +    },
> >>>> +    {
> >>>> +      /* Larger struct, zeroed out the unused values.  */
> >>>> +      .arg.inner.flags = O_RDONLY,
> >>>> +      .size = sizeof (struct open_how_ext),
> >>>> +    },
> >>>> +    {
> >>>> +      /* Larger struct, non-zeroed out the unused values.  */
> >>>> +      .arg.inner.flags = O_RDONLY,
> >>>> +      .arg.extra1 = 0xdeadbeef,
> >>>> +      .size = sizeof (struct open_how_ext),
> >>>> +      .err = E2BIG,
> >>>> +    },
> >>>> +    {
> >>>> +      /* Larger struct, non-zeroed out the unused values.  */
> >>>> +      .arg.inner.flags = O_RDONLY,
> >>>> +      .arg.extra2 = 0xdeadbeef,
> >>>> +      .size = sizeof (struct open_how_ext),
> >>>> +      .err = E2BIG,
> >>>> +    },
> >>>> +  };
> >>>> +
> >>>> +  for (struct struct_test *t = tests; t != array_end (tests); t++)
> >>>> +    {
> >>>> +      int fd = openat2 (AT_FDCWD, ".", (struct open_how *) &t->arg, t->size);
> >>>> +      if (fd == -1 && errno == ENOSYS)
> >>>> +       FAIL_UNSUPPORTED ("openat2 is not supported by the kernel");
> >>>> +
> >>>> +      if (t->err != 0)
> >>>> +       {
> >>>> +         TEST_COMPARE (fd, -1);
> >>>> +         TEST_COMPARE (errno, t->err);
> >>>> +       }
> >>>> +      else
> >>>> +       TEST_VERIFY (fd >= 0);
> >>>> +    }
> >>>> +
> >>>> +  return 0;
> >>>> +}
> >>>> +
> >>>> +static int
> >>>> +do_test_flags (void)
> >>>> +{
> >>>> +  static struct flag_test
> >>>> +  {
> >>>> +    struct open_how how;
> >>>> +    int err;
> >>>> +  } tests[] =
> >>>> +  {
> >>>> +    /* O_TMPFILE is incompatible with O_PATH and O_CREAT.  */
> >>>> +    { .how.flags = O_TMPFILE | O_PATH | O_RDWR, .err = EINVAL },
> >>>> +    { .how.flags = O_TMPFILE | O_CREAT | O_RDWR, .err = EINVAL },
> >>>> +
> >>>> +    /* O_PATH only permits certain other flags to be set ...  */
> >>>> +    { .how.flags = O_PATH | O_CLOEXEC },
> >>>> +    { .how.flags = O_PATH | O_DIRECTORY },
> >>>> +    { .how.flags = O_PATH | O_NOFOLLOW },
> >>>> +    /* ... and others are absolutely not permitted. */
> >>>> +    { .how.flags = O_PATH | O_RDWR, .err = EINVAL },
> >>>> +    { .how.flags = O_PATH | O_CREAT, .err = EINVAL },
> >>>> +    { .how.flags = O_PATH | O_EXCL, .err = EINVAL },
> >>>> +    { .how.flags = O_PATH | O_NOCTTY, .err = EINVAL },
> >>>> +    { .how.flags = O_PATH | O_DIRECT, .err = EINVAL },
> >>>> +
> >>>> +    /* ->mode must only be set with O_{CREAT,TMPFILE}. */
> >>>> +    { .how.flags = O_RDONLY, .how.mode = 0600, .err = EINVAL },
> >>>> +    { .how.flags = O_PATH,   .how.mode = 0600, .err = EINVAL },
> >>>> +    { .how.flags = O_CREAT,  .how.mode = 0600 },
> >>>> +    { .how.flags = O_TMPFILE | O_RDWR, .how.mode = 0600 },
> >>>> +    /* ->mode must only contain 0777 bits. */
> >>>> +    { .how.flags = O_CREAT, .how.mode = 0xFFFF, .err = EINVAL },
> >>>> +    { .how.flags = O_CREAT, .how.mode = 0xC000000000000000ULL, .err = EINVAL },
> >>>> +    { .how.flags = O_TMPFILE | O_RDWR, .how.mode = 0x1337, .err = EINVAL },
> >>>> +    { .how.flags = O_TMPFILE | O_RDWR, .how.mode = 0x0000A00000000000ULL,
> >>>> +      .err = EINVAL },
> >>>> +
> >>>> +    /* ->resolve flags must not conflict. */
> >>>> +    { .how.flags = O_RDONLY,
> >>>> +      .how.resolve = RESOLVE_BENEATH | RESOLVE_IN_ROOT,
> >>>> +      .err = EINVAL },
> >>>> +
> >>>> +    /* ->resolve must only contain RESOLVE_* flags.  */
> >>>> +    { .how.flags = O_RDONLY,
> >>>> +      .how.resolve = 0x1337, .err = EINVAL },
> >>>> +    { .how.flags = O_CREAT,
> >>>> +      .how.resolve = 0x1337, .err = EINVAL },
> >>>> +    { .how.flags = O_TMPFILE | O_RDWR,
> >>>> +      .how.resolve = 0x1337, .err = EINVAL },
> >>>> +    { .how.flags = O_PATH,
> >>>> +      .how.resolve = 0x1337, .err = EINVAL },
> >>>> +
> >>>> +    /* currently unknown upper 32 bit rejected.  */
> >>>> +    { .how.flags = O_RDONLY | (1ULL << 63),
> >>>> +      .how.resolve = 0, .err = EINVAL },
> >>>> +  };
> >>>> +
> >>>> +  for (struct flag_test *t = tests; t != array_end (tests); t++)
> >>>> +    {
> >>>> +      char *path;
> >>>> +      if (t->how.flags & O_CREAT)
> >>>> +       {
> >>>> +         int temp_fd = create_temp_file ("tst-openat2.", &path);
> >>>> +         TEST_VERIFY_EXIT (temp_fd != -1);
> >>>> +         xunlink (path);
> >>>> +       }
> >>>> +      else
> >>>> +       path = (char *) ".";
> >>>> +
> >>>> +      int fd = openat2 (AT_FDCWD, path, &t->how, sizeof (struct open_how));
> >>>> +      if (fd != 0 && errno == EOPNOTSUPP)
> >>>> +       {
> >>>> +         /* Skip the testcase if FS does not support the operation (e.g.
> >>>> +            valid O_TMPFILE on NFS).  */
> >>>> +         continue;
> >>>> +       }
> >>>> +
> >>>> +      if (t->err != 0)
> >>>> +       {
> >>>> +         TEST_COMPARE (fd, -1);
> >>>> +         TEST_COMPARE (errno, t->err);
> >>>> +       }
> >>>> +      else
> >>>> +       TEST_VERIFY (fd >= 0);
> >>>> +    }
> >>>> +
> >>>> +  return 0;
> >>>> +}
> >>>> +
> >>>> +static int
> >>>> +do_test_basic (void)
> >>>> +{
> >>>> +  int fd;
> >>>> +
> >>>> +  fd = openat2 (dir_fd,
> >>>> +               "some-file",
> >>>> +               &(struct open_how)
> >>>> +               {
> >>>> +                 .flags = O_CREAT|O_RDWR|O_EXCL,
> >>>> +                 .mode = 0666,
> >>>> +               },
> >>>> +               sizeof (struct open_how));
> >>>> +  TEST_VERIFY (fd != -1);
> >>>> +
> >>>> +  xwrite (fd, "hello", 5);
> >>>> +
> >>>> +  /* Before closing the file, try using this file descriptor to open
> >>>> +     another file.  This must fail.  */
> >>>> +  {
> >>>> +    int fd2 = openat2 (fd,
> >>>> +                      "should-not-work",
> >>>> +                      &(struct open_how)
> >>>> +                      {
> >>>> +                        .flags = O_CREAT|O_RDWR|O_EXCL,
> >>>> +                        .mode = 0666,
> >>>> +                      },
> >>>> +                      sizeof (struct open_how));
> >>>> +    TEST_COMPARE (fd2, -1);
> >>>> +    TEST_COMPARE (errno, ENOTDIR);
> >>>> +  }
> >>>> +
> >>>> +  /* Remove the created file.  */
> >>>> +  int cwdfd = xopen (".", O_RDONLY | O_DIRECTORY, 0);
> >>>> +  TEST_COMPARE (fchdir (dir_fd), 0);
> >>>> +  xunlink ("some-file");
> >>>> +  TEST_COMPARE (fchdir (cwdfd), 0);
> >>>> +
> >>>> +  xclose (dir_fd);
> >>>> +  xclose (cwdfd);
> >>>> +
> >>>> +  fd = openat2 (dir_fd,
> >>>> +               "some-file",
> >>>> +               &(struct open_how)
> >>>> +               {
> >>>> +                 .flags = O_CREAT|O_RDWR|O_EXCL,
> >>>> +                 .mode = 0666,
> >>>> +               },
> >>>> +               sizeof (struct open_how));
> >>>> +  TEST_COMPARE (fd, -1);
> >>>> +  TEST_COMPARE (errno, EBADF);
> >>>> +
> >>>> +  return 0;
> >>>> +}
> >>>> +
> >>>> +static int
> >>>> +do_test (void)
> >>>> +{
> >>>> +  do_test_struct ();
> >>>> +  do_test_flags ();
> >>>> +  do_test_basic ();
> >>>> +
> >>>> +  return 0;
> >>>> +}
> >>>> +
> >>>> +#include <support/test-driver.c>
> >>>> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> >>>> index aea7848ed6..a7f177c8a8 100644
> >>>> --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> >>>> @@ -2744,6 +2744,7 @@ GLIBC_2.4 sys_errlist D 0x420
> >>>>  GLIBC_2.4 sys_nerr D 0x4
> >>>>  GLIBC_2.4 unlinkat F
> >>>>  GLIBC_2.4 unshare F
> >>>> +GLIBC_2.40 openat2 F
> >>>>  GLIBC_2.5 __readlinkat_chk F
> >>>>  GLIBC_2.5 inet6_opt_append F
> >>>>  GLIBC_2.5 inet6_opt_find F
> >>>> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> >>>> index 4ab3681914..00dfc8f1e7 100644
> >>>> --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> >>>> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> >>>> @@ -2763,3 +2763,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_ul F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_ull F
> >>>>  GLIBC_2.39 stdc_trailing_zeros_us F
> >>>> +GLIBC_2.40 openat2 F
> >>>> --
> >>>> 2.34.1
> >>>>
Adhemerval Zanella April 25, 2024, 4:10 p.m. UTC | #6
On 25/04/24 11:10, enh wrote:
> On Thu, Apr 25, 2024 at 7:01 AM Adhemerval Zanella Netto
> <adhemerval.zanella@linaro.org> wrote:
>>
>>
>>
>> On 24/04/24 18:18, enh wrote:
>>> On Wed, Apr 24, 2024 at 11:05 AM Adhemerval Zanella Netto
>>> <adhemerval.zanella@linaro.org> wrote:
>>>>
>>>> That's a good question, since we currently do not export any kernel interface
>>>> which this new struct/size argument passing (we do use clone3, but it is
>>>> just internally). For a libc/kernel interface, it should not matter; but from
>>>> a libc exported symbol we indeed need to be more careful.
>>>>
>>>> From a glibc perpectiveI think we will need to *not* include kernel UAPI header,
>>>> remove the size from the wrapper, and add some slack size on open_how for
>>>> future extension.  It makes open_how extensions to not require new symbol
>>>> version in the near future (similar to what was done for statx).
>>>
>>> i think statx did that _in uapi_, no? there's already padding
>>> upstream. (that's a much better way to do these things from a libc
>>> perspective; if someone talks to the kernel folks, it's worth trying
>>> to encourage them to do more of that, and less of the openat2() or
>>> sched_setattr().)
>>
>> Yes, the statx added some spare fields because it does not have the extra
>> size parameter and an statx extension that extends further will require
>> another syscall (this is the same for sched_setattr). The openat2 approach
>> is not bad, it solves this issue.
> 
> it is bad, because it solves the _kernel_ problem by creating a
> userspace problem.
> 
> (not versioning the _syscall_ is fine, as long as you version the
> _struct_ -- and we have a void* and size_t in the libc api -- but not
> versioning either just pushes new problems onto userspace. userspace
> would be better off with multiple syscalls!)

I tend to agree, but this is for the case where libc would want to interop
with linux headers.  And the problem is kABI currently does not have this
concept of the struct versions, for instance clone3 UAPI updated clone_args
without any renaming (it at least exports the expected version size, unlikely
open_how).

So I think for such cases where the kABI struct might change depending of
header version it does make sense to version the struct.  I am not sure
where kernel would be willing to do (cced Aleksa which was the one that
introduced openat2).

Doing so would allow libc to include the kernel header, if present.
Florian Weimer April 29, 2024, 1:38 p.m. UTC | #7
* Adhemerval Zanella:

> diff --git a/sysdeps/unix/sysv/linux/bits/openat2.h b/sysdeps/unix/sysv/linux/bits/openat2.h
> new file mode 100644
> index 0000000000..a07984dace
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/bits/openat2.h

> +#ifndef __glibc_has_open_how
> +/* Arguments for how openat2 should open the target path.  */
> +struct open_how
> +{
> +  __uint64_t flags;
> +  __uint64_t mode;
> +  __uint64_t resolve;
> +};
> +#endif

I think this needs better documentation that this is an extensible
struct which must only be used with the openat2 function, and must not
be nested in other structs or exposed in any way where the exact struct
size matters.

Symbol versioning is not able to solve this problem because the only
symbol involved here (openat2) does not actually depend on the struct
size.

> diff --git a/sysdeps/unix/sysv/linux/tst-openat2.c b/sysdeps/unix/sysv/linux/tst-openat2.c
> new file mode 100644
> index 0000000000..d0c26f2bce
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/tst-openat2.c

> +static int
> +do_test_struct (void)
> +{
> +  static struct struct_test
> +  {
> +    struct open_how_ext
> +    {
> +      struct open_how inner;
> +      int extra1;
> +      int extra2;
> +      int extra3;
> +    } arg;
> +    size_t size;
> +    int err;
> +  } tests[] =
> +  {
> +    {
> +      /* Zero size.  */
> +      .arg.inner.flags = O_RDONLY,
> +      .size = 0,
> +      .err = EINVAL,
> +    },
> +    {
> +      /* Normal struct.  */
> +      .arg.inner.flags = O_RDONLY,
> +      .size = sizeof (struct open_how),
> +    },
> +    {
> +      /* Larger struct, zeroed out the unused values.  */
> +      .arg.inner.flags = O_RDONLY,
> +      .size = sizeof (struct open_how_ext),
> +    },
> +    {
> +      /* Larger struct, non-zeroed out the unused values.  */
> +      .arg.inner.flags = O_RDONLY,
> +      .arg.extra1 = 0xdeadbeef,
> +      .size = sizeof (struct open_how_ext),
> +      .err = E2BIG,
> +    },
> +    {
> +      /* Larger struct, non-zeroed out the unused values.  */
> +      .arg.inner.flags = O_RDONLY,
> +      .arg.extra2 = 0xdeadbeef,
> +      .size = sizeof (struct open_how_ext),
> +      .err = E2BIG,
> +    },

These tests will require constant maintenance on kernel upgrades.  Are
they really helpful?

Thanks,
Florian
Adhemerval Zanella May 1, 2024, 2:14 p.m. UTC | #8
On 29/04/24 10:38, Florian Weimer wrote:
> * Adhemerval Zanella:
> 
>> diff --git a/sysdeps/unix/sysv/linux/bits/openat2.h b/sysdeps/unix/sysv/linux/bits/openat2.h
>> new file mode 100644
>> index 0000000000..a07984dace
>> --- /dev/null
>> +++ b/sysdeps/unix/sysv/linux/bits/openat2.h
> 
>> +#ifndef __glibc_has_open_how
>> +/* Arguments for how openat2 should open the target path.  */
>> +struct open_how
>> +{
>> +  __uint64_t flags;
>> +  __uint64_t mode;
>> +  __uint64_t resolve;
>> +};
>> +#endif
> 
> I think this needs better documentation that this is an extensible
> struct which must only be used with the openat2 function, and must not
> be nested in other structs or exposed in any way where the exact struct
> size matters.
> 
> Symbol versioning is not able to solve this problem because the only
> symbol involved here (openat2) does not actually depend on the struct
> size.

Another possibility would to not use the kernel definition and instead
add a 'open_how' with some spare size (kernel will only reject large
sizes if is not zero-initialized and it does not support the extra fields).
It will require glibc to update the new fields on kernel updates tough.

Indeed we don't need symbol versioning, we can infer the struct layout
by the size alone.

> 
>> diff --git a/sysdeps/unix/sysv/linux/tst-openat2.c b/sysdeps/unix/sysv/linux/tst-openat2.c
>> new file mode 100644
>> index 0000000000..d0c26f2bce
>> --- /dev/null
>> +++ b/sysdeps/unix/sysv/linux/tst-openat2.c
> 
>> +static int
>> +do_test_struct (void)
>> +{
>> +  static struct struct_test
>> +  {
>> +    struct open_how_ext
>> +    {
>> +      struct open_how inner;
>> +      int extra1;
>> +      int extra2;
>> +      int extra3;
>> +    } arg;
>> +    size_t size;
>> +    int err;
>> +  } tests[] =
>> +  {
>> +    {
>> +      /* Zero size.  */
>> +      .arg.inner.flags = O_RDONLY,
>> +      .size = 0,
>> +      .err = EINVAL,
>> +    },
>> +    {
>> +      /* Normal struct.  */
>> +      .arg.inner.flags = O_RDONLY,
>> +      .size = sizeof (struct open_how),
>> +    },
>> +    {
>> +      /* Larger struct, zeroed out the unused values.  */
>> +      .arg.inner.flags = O_RDONLY,
>> +      .size = sizeof (struct open_how_ext),
>> +    },
>> +    {
>> +      /* Larger struct, non-zeroed out the unused values.  */
>> +      .arg.inner.flags = O_RDONLY,
>> +      .arg.extra1 = 0xdeadbeef,
>> +      .size = sizeof (struct open_how_ext),
>> +      .err = E2BIG,
>> +    },
>> +    {
>> +      /* Larger struct, non-zeroed out the unused values.  */
>> +      .arg.inner.flags = O_RDONLY,
>> +      .arg.extra2 = 0xdeadbeef,
>> +      .size = sizeof (struct open_how_ext),
>> +      .err = E2BIG,
>> +    },
> 
> These tests will require constant maintenance on kernel upgrades.  Are
> they really helpful?

It would if the idea is to try to keep the fallback interface in sync
with kernel (or if we skip kernel inclusion altogether).  

I don't have a strong opinion which strategy we should use for these new
kernel interfaces.
diff mbox series

Patch

diff --git a/NEWS b/NEWS
index cf6078cf20..eaaa02cb4e 100644
--- a/NEWS
+++ b/NEWS
@@ -26,6 +26,10 @@  Major new features:
   more extensive verification tests for AT_SECURE programs and not meant to
   be a security feature.
 
+* On Linux, the openat2 function has been added.  It is an extension of
+  openat and provides a superset of its functionality.  It is supported only
+  in LFS mode and as other open like it is a cancellable entrypoint.
+
 Deprecated and removed features, and other changes affecting compatibility:
 
 * Architectures which use a 32-bit seconds-since-epoch field in struct
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index 415aa1f14d..4ae8ec6dc6 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -133,6 +133,7 @@  sysdep_headers += \
   bits/mman-linux.h \
   bits/mman-map-flags-generic.h \
   bits/mman-shared.h \
+  bits/openat2.h \
   bits/procfs-extra.h \
   bits/procfs-id.h \
   bits/procfs-prregset.h \
@@ -591,6 +592,7 @@  sysdep_routines += \
   internal_statvfs \
   open64_nocancel \
   open_nocancel \
+  openat2 \
   openat64_nocancel \
   openat_nocancel \
   pread64_nocancel \
@@ -611,7 +613,19 @@  tests += \
   tst-fallocate64 \
   tst-getcwd-smallbuff \
   tst-o_path-locks \
+  tst-openat2 \
   # tests
+
+tests-special += \
+  $(objpfx)tst-openat2-consts.out \
+  # tests-special
+$(objpfx)tst-openat2-consts.out: ../sysdeps/unix/sysv/linux/tst-openat2-consts.py
+	$(sysdeps-linux-python) \
+	  ../sysdeps/unix/sysv/linux/tst-openat2-consts.py \
+	    $(sysdeps-linux-python-cc) \
+	  < /dev/null > $@ 2>&1; $(evaluate-test)
+$(objpfx)tst-openat2-consts.out: $(sysdeps-linux-python-deps)
+
 endif
 
 ifeq ($(subdir),elf)
diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions
index 268ba1b6ac..65da2b617a 100644
--- a/sysdeps/unix/sysv/linux/Versions
+++ b/sysdeps/unix/sysv/linux/Versions
@@ -328,6 +328,9 @@  libc {
     posix_spawnattr_getcgroup_np;
     posix_spawnattr_setcgroup_np;
   }
+  GLIBC_2.40 {
+    openat2;
+  }
   GLIBC_PRIVATE {
     # functions used in other libraries
     __syscall_rt_sigqueueinfo;
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 68eeca1c08..0b9bd8ae62 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2748,3 +2748,4 @@  GLIBC_2.39 stdc_trailing_zeros_ui F
 GLIBC_2.39 stdc_trailing_zeros_ul F
 GLIBC_2.39 stdc_trailing_zeros_ull F
 GLIBC_2.39 stdc_trailing_zeros_us F
+GLIBC_2.40 openat2 F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 34c187b721..c0bd27d617 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -3095,6 +3095,7 @@  GLIBC_2.4 wcstold F
 GLIBC_2.4 wcstold_l F
 GLIBC_2.4 wprintf F
 GLIBC_2.4 wscanf F
+GLIBC_2.40 openat2 F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index 916c18ea94..965438e7a7 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -2509,3 +2509,4 @@  GLIBC_2.39 stdc_trailing_zeros_ui F
 GLIBC_2.39 stdc_trailing_zeros_ul F
 GLIBC_2.39 stdc_trailing_zeros_ull F
 GLIBC_2.39 stdc_trailing_zeros_us F
+GLIBC_2.40 openat2 F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index ea95de282a..e69ed8c903 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -2801,6 +2801,7 @@  GLIBC_2.4 xdrstdio_create F
 GLIBC_2.4 xencrypt F
 GLIBC_2.4 xprt_register F
 GLIBC_2.4 xprt_unregister F
+GLIBC_2.40 openat2 F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index 1cdbc983e1..70fd425869 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -2798,6 +2798,7 @@  GLIBC_2.4 xdrstdio_create F
 GLIBC_2.4 xencrypt F
 GLIBC_2.4 xprt_register F
 GLIBC_2.4 xprt_unregister F
+GLIBC_2.40 openat2 F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
index 628612b885..279aa2b8eb 100644
--- a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
+++ b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
@@ -451,6 +451,28 @@  extern int name_to_handle_at (int __dfd, const char *__name,
 extern int open_by_handle_at (int __mountdirfd, struct file_handle *__handle,
 			      int __flags);
 
+#ifdef __has_include
+# if __has_include ("linux/openat2.h")
+#  include "linux/openat2.h"
+#  define __glibc_has_open_how 1
+# endif
+#endif
+
+#include <bits/openat2.h>
+
+/* Similar to `openat' but the arguments are packed on HOW with the size
+   USIZE.  If flags and mode from HOW are non-zero, then openat2 operates
+   like openat.
+
+   Unlike openat2, unknown or invalid flags result in an error (EINVAL),
+   rather than being ignored.  The mode must be zero unless one O_CREAT
+   or O_TMPFILE are set.
+
+   The kernel does not support legacy non-LFS interface.  */
+extern int openat2 (int __dfd, const char *__filename, struct open_how *__how,
+		    size_t __usize)
+     __nonnull ((2, 3));
+
 #endif	/* use GNU */
 
 __END_DECLS
diff --git a/sysdeps/unix/sysv/linux/bits/openat2.h b/sysdeps/unix/sysv/linux/bits/openat2.h
new file mode 100644
index 0000000000..a07984dace
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/bits/openat2.h
@@ -0,0 +1,61 @@ 
+/* openat2 definition.  Linux specific.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef	_FCNTL_H
+# error "Never use <bits/openat2.h> directly; include <fcntl.h> instead."
+#endif
+
+#ifndef __glibc_has_open_how
+/* Arguments for how openat2 should open the target path.  */
+struct open_how
+{
+  __uint64_t flags;
+  __uint64_t mode;
+  __uint64_t resolve;
+};
+#endif
+
+/* how->resolve flags for openat2. */
+#ifndef RESOLVE_NO_XDEV
+# define RESOLVE_NO_XDEV	0x01 /* Block mount-point crossings
+					(includes bind-mounts).  */
+#endif
+#ifndef RESOLVE_NO_MAGICLINKS
+# define RESOLVE_NO_MAGICLINKS	0x02 /* Block traversal through procfs-style
+					"magic-links".  */
+#endif
+#ifndef RESOLVE_NO_SYMLINKS
+# define RESOLVE_NO_SYMLINKS	0x04 /* Block traversal through all symlinks
+					(implies OEXT_NO_MAGICLINKS).  */
+#endif
+#ifndef RESOLVE_BENEATH
+# define RESOLVE_BENEATH	0x08 /* Block "lexical" trickery like
+					"..", symlinks, and absolute
+					paths which escape the dirfd.  */
+#endif
+#ifndef RESOLVE_IN_ROOT
+# define RESOLVE_IN_ROOT	0x10 /* Make all jumps to "/" and ".."
+					be scoped inside the dirfd
+					(similar to chroot).  */
+#endif
+#ifndef RESOLVE_CACHED
+# define RESOLVE_CACHED		0x20 /* Only complete if resolution can be
+					completed through cached lookup. May
+					return -EAGAIN if that's not
+					possible.  */
+#endif
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index 96d45961e2..c81ea43dc1 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2785,3 +2785,4 @@  GLIBC_2.39 stdc_trailing_zeros_ui F
 GLIBC_2.39 stdc_trailing_zeros_ul F
 GLIBC_2.39 stdc_trailing_zeros_ull F
 GLIBC_2.39 stdc_trailing_zeros_us F
+GLIBC_2.40 openat2 F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index fbcd60c2b3..23eec25d8a 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2821,6 +2821,7 @@  GLIBC_2.4 sys_errlist D 0x400
 GLIBC_2.4 sys_nerr D 0x4
 GLIBC_2.4 unlinkat F
 GLIBC_2.4 unshare F
+GLIBC_2.40 openat2 F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index c989b433c0..4ce2afb147 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -3005,6 +3005,7 @@  GLIBC_2.4 sys_errlist D 0x210
 GLIBC_2.4 sys_nerr D 0x4
 GLIBC_2.4 unlinkat F
 GLIBC_2.4 unshare F
+GLIBC_2.40 openat2 F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
index 0023ec1fa1..be76251b28 100644
--- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
@@ -2269,3 +2269,4 @@  GLIBC_2.39 stdc_trailing_zeros_ui F
 GLIBC_2.39 stdc_trailing_zeros_ul F
 GLIBC_2.39 stdc_trailing_zeros_ull F
 GLIBC_2.39 stdc_trailing_zeros_us F
+GLIBC_2.40 openat2 F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index d9bd6a9b56..5ff3db5035 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -2781,6 +2781,7 @@  GLIBC_2.4 xdrstdio_create F
 GLIBC_2.4 xencrypt F
 GLIBC_2.4 xprt_register F
 GLIBC_2.4 xprt_unregister F
+GLIBC_2.40 openat2 F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 439796d693..39645248af 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2948,6 +2948,7 @@  GLIBC_2.4 sys_errlist D 0x210
 GLIBC_2.4 sys_nerr D 0x4
 GLIBC_2.4 unlinkat F
 GLIBC_2.4 unshare F
+GLIBC_2.40 openat2 F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index 1069d3252c..2f917724de 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2834,3 +2834,4 @@  GLIBC_2.39 stdc_trailing_zeros_ui F
 GLIBC_2.39 stdc_trailing_zeros_ul F
 GLIBC_2.39 stdc_trailing_zeros_ull F
 GLIBC_2.39 stdc_trailing_zeros_us F
+GLIBC_2.40 openat2 F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 17abe08c8b..6cc64f97b5 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2831,3 +2831,4 @@  GLIBC_2.39 stdc_trailing_zeros_ui F
 GLIBC_2.39 stdc_trailing_zeros_ul F
 GLIBC_2.39 stdc_trailing_zeros_ull F
 GLIBC_2.39 stdc_trailing_zeros_us F
+GLIBC_2.40 openat2 F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 799e508950..ae5b95bc76 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2909,6 +2909,7 @@  GLIBC_2.4 renameat F
 GLIBC_2.4 symlinkat F
 GLIBC_2.4 unlinkat F
 GLIBC_2.4 unshare F
+GLIBC_2.40 openat2 F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 1c10996cbc..434e997937 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2907,6 +2907,7 @@  GLIBC_2.4 renameat F
 GLIBC_2.4 symlinkat F
 GLIBC_2.4 unlinkat F
 GLIBC_2.4 unshare F
+GLIBC_2.40 openat2 F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index 03d9655f26..5dc2996fcc 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2915,6 +2915,7 @@  GLIBC_2.4 renameat F
 GLIBC_2.4 symlinkat F
 GLIBC_2.4 unlinkat F
 GLIBC_2.4 unshare F
+GLIBC_2.40 openat2 F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 05e402ed30..865dc5e7f1 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2817,6 +2817,7 @@  GLIBC_2.4 renameat F
 GLIBC_2.4 symlinkat F
 GLIBC_2.4 unlinkat F
 GLIBC_2.4 unshare F
+GLIBC_2.40 openat2 F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 3aa81766aa..12775fdad5 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2873,3 +2873,4 @@  GLIBC_2.39 stdc_trailing_zeros_ui F
 GLIBC_2.39 stdc_trailing_zeros_ul F
 GLIBC_2.39 stdc_trailing_zeros_ull F
 GLIBC_2.39 stdc_trailing_zeros_us F
+GLIBC_2.40 openat2 F
diff --git a/sysdeps/unix/sysv/linux/openat2.c b/sysdeps/unix/sysv/linux/openat2.c
new file mode 100644
index 0000000000..a2b134bab0
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/openat2.c
@@ -0,0 +1,29 @@ 
+/* Linux openat2 syscall implementation.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <fcntl.h>
+#include <bits/openat2.h>
+#include <sysdep-cancel.h>
+
+int
+__openat2 (int dfd, const char *filename, struct open_how *how,
+	   size_t usize)
+{
+  return SYSCALL_CANCEL (openat2, dfd, filename, how, usize);
+}
+weak_alias (__openat2, openat2)
diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist
index c40c843aaf..2835436011 100644
--- a/sysdeps/unix/sysv/linux/or1k/libc.abilist
+++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist
@@ -2255,3 +2255,4 @@  GLIBC_2.39 stdc_trailing_zeros_ui F
 GLIBC_2.39 stdc_trailing_zeros_ul F
 GLIBC_2.39 stdc_trailing_zeros_ull F
 GLIBC_2.39 stdc_trailing_zeros_us F
+GLIBC_2.40 openat2 F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 9714305608..3b70a56944 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -3138,6 +3138,7 @@  GLIBC_2.4 wcstold F
 GLIBC_2.4 wcstold_l F
 GLIBC_2.4 wprintf F
 GLIBC_2.4 wscanf F
+GLIBC_2.40 openat2 F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 0beb52c542..677c9a75de 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -3183,6 +3183,7 @@  GLIBC_2.4 wcstold F
 GLIBC_2.4 wcstold_l F
 GLIBC_2.4 wprintf F
 GLIBC_2.4 wscanf F
+GLIBC_2.40 openat2 F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index cfc2ebd3ec..10fc3c89dc 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2892,6 +2892,7 @@  GLIBC_2.4 wcstold F
 GLIBC_2.4 wcstold_l F
 GLIBC_2.4 wprintf F
 GLIBC_2.4 wscanf F
+GLIBC_2.40 openat2 F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 8c9efc5a16..713fa1d1c8 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2968,3 +2968,4 @@  GLIBC_2.39 stdc_trailing_zeros_ui F
 GLIBC_2.39 stdc_trailing_zeros_ul F
 GLIBC_2.39 stdc_trailing_zeros_ull F
 GLIBC_2.39 stdc_trailing_zeros_us F
+GLIBC_2.40 openat2 F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index 6397a9cb91..550ba877ef 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -2512,3 +2512,4 @@  GLIBC_2.39 stdc_trailing_zeros_ul F
 GLIBC_2.39 stdc_trailing_zeros_ull F
 GLIBC_2.39 stdc_trailing_zeros_us F
 GLIBC_2.40 __riscv_hwprobe F
+GLIBC_2.40 openat2 F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index 71bbf94f66..8bf9f309b7 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2712,3 +2712,4 @@  GLIBC_2.39 stdc_trailing_zeros_ul F
 GLIBC_2.39 stdc_trailing_zeros_ull F
 GLIBC_2.39 stdc_trailing_zeros_us F
 GLIBC_2.40 __riscv_hwprobe F
+GLIBC_2.40 openat2 F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index a7467e2850..08bc3d6f8b 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -3136,6 +3136,7 @@  GLIBC_2.4 wcstold F
 GLIBC_2.4 wcstold_l F
 GLIBC_2.4 wprintf F
 GLIBC_2.4 wscanf F
+GLIBC_2.40 openat2 F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index fd1cb2972d..e25afff581 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2929,6 +2929,7 @@  GLIBC_2.4 wcstold F
 GLIBC_2.4 wcstold_l F
 GLIBC_2.4 wprintf F
 GLIBC_2.4 wscanf F
+GLIBC_2.40 openat2 F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index ff6e6b1a13..499de50ee0 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2828,6 +2828,7 @@  GLIBC_2.4 sys_errlist D 0x210
 GLIBC_2.4 sys_nerr D 0x4
 GLIBC_2.4 unlinkat F
 GLIBC_2.4 unshare F
+GLIBC_2.40 openat2 F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index 449d92bbc5..bdd9c600f0 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2825,6 +2825,7 @@  GLIBC_2.4 sys_errlist D 0x210
 GLIBC_2.4 sys_nerr D 0x4
 GLIBC_2.4 unlinkat F
 GLIBC_2.4 unshare F
+GLIBC_2.40 openat2 F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index e615be759a..b20dd43d47 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -3157,6 +3157,7 @@  GLIBC_2.4 wcstold F
 GLIBC_2.4 wcstold_l F
 GLIBC_2.4 wprintf F
 GLIBC_2.4 wscanf F
+GLIBC_2.40 openat2 F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index bd36431dd7..19981aa981 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2793,6 +2793,7 @@  GLIBC_2.4 sys_errlist D 0x430
 GLIBC_2.4 sys_nerr D 0x4
 GLIBC_2.4 unlinkat F
 GLIBC_2.4 unshare F
+GLIBC_2.40 openat2 F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/tst-openat2-consts.py b/sysdeps/unix/sysv/linux/tst-openat2-consts.py
new file mode 100755
index 0000000000..1623fafd94
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-openat2-consts.py
@@ -0,0 +1,63 @@ 
+#!/usr/bin/python3
+# Test that glibc's sys/openat2.h constants match the kernel's.
+# Copyright (C) 2024 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+#
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <https://www.gnu.org/licenses/>.
+
+import argparse
+import sys
+
+import glibcextract
+import glibcsyscalls
+
+
+def main():
+    """The main entry point."""
+    parser = argparse.ArgumentParser(
+        description="Test that glibc's sys/openat2.h constants "
+        "match the kernel's.")
+    parser.add_argument('--cc', metavar='CC',
+                        help='C compiler (including options) to use')
+    args = parser.parse_args()
+
+    if glibcextract.compile_c_snippet(
+            '#include <linux/openat2.h>',
+            args.cc).returncode != 0:
+        sys.exit (77)
+
+    linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
+    # Constants in glibc were updated to match Linux v6.8.  When glibc
+    # constants are updated this value should be updated to match the
+    # released kernel version from which the constants were taken.
+    linux_version_glibc = (6, 8)
+    def check(cte, exclude=None):
+        return glibcextract.compare_macro_consts(
+                '#define _FCNTL_H\n'
+                '#include <stdint.h>\n'
+                '#include <bits/openat2.h>\n',
+                '#include <asm/fcntl.h>\n'
+                '#include <linux/openat2.h>\n',
+                args.cc,
+                cte,
+                exclude,
+                linux_version_glibc > linux_version_headers,
+                linux_version_headers > linux_version_glibc)
+
+    status = check('RESOLVE.*')
+    sys.exit(status)
+
+if __name__ == '__main__':
+    main()
diff --git a/sysdeps/unix/sysv/linux/tst-openat2.c b/sysdeps/unix/sysv/linux/tst-openat2.c
new file mode 100644
index 0000000000..d0c26f2bce
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-openat2.c
@@ -0,0 +1,259 @@ 
+/* Linux openat2 tests.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+/* openat2 always return a file descriptor in LFS mode.  */
+#define _FILE_OFFSET_BITS 64
+
+#include <array_length.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <support/check.h>
+#include <support/temp_file.h>
+#include <support/xunistd.h>
+
+static int dir_fd;
+
+static void
+do_prepare (int argc, char *argv[])
+{
+  char *temp_dir = support_create_temp_directory ("tst-openat2");
+  dir_fd = xopen (temp_dir, O_RDONLY | O_DIRECTORY, 0);
+}
+#define PREPARE do_prepare
+
+static int
+do_test_struct (void)
+{
+  static struct struct_test
+  {
+    struct open_how_ext
+    {
+      struct open_how inner;
+      int extra1;
+      int extra2;
+      int extra3;
+    } arg;
+    size_t size;
+    int err;
+  } tests[] =
+  {
+    {
+      /* Zero size.  */
+      .arg.inner.flags = O_RDONLY,
+      .size = 0,
+      .err = EINVAL,
+    },
+    {
+      /* Normal struct.  */
+      .arg.inner.flags = O_RDONLY,
+      .size = sizeof (struct open_how),
+    },
+    {
+      /* Larger struct, zeroed out the unused values.  */
+      .arg.inner.flags = O_RDONLY,
+      .size = sizeof (struct open_how_ext),
+    },
+    {
+      /* Larger struct, non-zeroed out the unused values.  */
+      .arg.inner.flags = O_RDONLY,
+      .arg.extra1 = 0xdeadbeef,
+      .size = sizeof (struct open_how_ext),
+      .err = E2BIG,
+    },
+    {
+      /* Larger struct, non-zeroed out the unused values.  */
+      .arg.inner.flags = O_RDONLY,
+      .arg.extra2 = 0xdeadbeef,
+      .size = sizeof (struct open_how_ext),
+      .err = E2BIG,
+    },
+  };
+
+  for (struct struct_test *t = tests; t != array_end (tests); t++)
+    {
+      int fd = openat2 (AT_FDCWD, ".", (struct open_how *) &t->arg, t->size);
+      if (fd == -1 && errno == ENOSYS)
+	FAIL_UNSUPPORTED ("openat2 is not supported by the kernel");
+
+      if (t->err != 0)
+	{
+	  TEST_COMPARE (fd, -1);
+	  TEST_COMPARE (errno, t->err);
+	}
+      else
+	TEST_VERIFY (fd >= 0);
+    }
+
+  return 0;
+}
+
+static int
+do_test_flags (void)
+{
+  static struct flag_test
+  {
+    struct open_how how;
+    int err;
+  } tests[] =
+  {
+    /* O_TMPFILE is incompatible with O_PATH and O_CREAT.  */
+    { .how.flags = O_TMPFILE | O_PATH | O_RDWR, .err = EINVAL },
+    { .how.flags = O_TMPFILE | O_CREAT | O_RDWR, .err = EINVAL },
+
+    /* O_PATH only permits certain other flags to be set ...  */
+    { .how.flags = O_PATH | O_CLOEXEC },
+    { .how.flags = O_PATH | O_DIRECTORY },
+    { .how.flags = O_PATH | O_NOFOLLOW },
+    /* ... and others are absolutely not permitted. */
+    { .how.flags = O_PATH | O_RDWR, .err = EINVAL },
+    { .how.flags = O_PATH | O_CREAT, .err = EINVAL },
+    { .how.flags = O_PATH | O_EXCL, .err = EINVAL },
+    { .how.flags = O_PATH | O_NOCTTY, .err = EINVAL },
+    { .how.flags = O_PATH | O_DIRECT, .err = EINVAL },
+
+    /* ->mode must only be set with O_{CREAT,TMPFILE}. */
+    { .how.flags = O_RDONLY, .how.mode = 0600, .err = EINVAL },
+    { .how.flags = O_PATH,   .how.mode = 0600, .err = EINVAL },
+    { .how.flags = O_CREAT,  .how.mode = 0600 },
+    { .how.flags = O_TMPFILE | O_RDWR, .how.mode = 0600 },
+    /* ->mode must only contain 0777 bits. */
+    { .how.flags = O_CREAT, .how.mode = 0xFFFF, .err = EINVAL },
+    { .how.flags = O_CREAT, .how.mode = 0xC000000000000000ULL, .err = EINVAL },
+    { .how.flags = O_TMPFILE | O_RDWR, .how.mode = 0x1337, .err = EINVAL },
+    { .how.flags = O_TMPFILE | O_RDWR, .how.mode = 0x0000A00000000000ULL,
+      .err = EINVAL },
+
+    /* ->resolve flags must not conflict. */
+    { .how.flags = O_RDONLY,
+      .how.resolve = RESOLVE_BENEATH | RESOLVE_IN_ROOT,
+      .err = EINVAL },
+
+    /* ->resolve must only contain RESOLVE_* flags.  */
+    { .how.flags = O_RDONLY,
+      .how.resolve = 0x1337, .err = EINVAL },
+    { .how.flags = O_CREAT,
+      .how.resolve = 0x1337, .err = EINVAL },
+    { .how.flags = O_TMPFILE | O_RDWR,
+      .how.resolve = 0x1337, .err = EINVAL },
+    { .how.flags = O_PATH,
+      .how.resolve = 0x1337, .err = EINVAL },
+
+    /* currently unknown upper 32 bit rejected.  */
+    { .how.flags = O_RDONLY | (1ULL << 63),
+      .how.resolve = 0, .err = EINVAL },
+  };
+
+  for (struct flag_test *t = tests; t != array_end (tests); t++)
+    {
+      char *path;
+      if (t->how.flags & O_CREAT)
+	{
+	  int temp_fd = create_temp_file ("tst-openat2.", &path);
+	  TEST_VERIFY_EXIT (temp_fd != -1);
+	  xunlink (path);
+	}
+      else
+	path = (char *) ".";
+
+      int fd = openat2 (AT_FDCWD, path, &t->how, sizeof (struct open_how));
+      if (fd != 0 && errno == EOPNOTSUPP)
+	{
+	  /* Skip the testcase if FS does not support the operation (e.g.
+	     valid O_TMPFILE on NFS).  */
+	  continue;
+	}
+
+      if (t->err != 0)
+	{
+	  TEST_COMPARE (fd, -1);
+	  TEST_COMPARE (errno, t->err);
+	}
+      else
+	TEST_VERIFY (fd >= 0);
+    }
+
+  return 0;
+}
+
+static int
+do_test_basic (void)
+{
+  int fd;
+
+  fd = openat2 (dir_fd,
+		"some-file",
+		&(struct open_how)
+		{
+		  .flags = O_CREAT|O_RDWR|O_EXCL,
+		  .mode = 0666,
+		},
+		sizeof (struct open_how));
+  TEST_VERIFY (fd != -1);
+
+  xwrite (fd, "hello", 5);
+
+  /* Before closing the file, try using this file descriptor to open
+     another file.  This must fail.  */
+  {
+    int fd2 = openat2 (fd,
+		       "should-not-work",
+		       &(struct open_how)
+		       {
+			 .flags = O_CREAT|O_RDWR|O_EXCL,
+			 .mode = 0666,
+		       },
+		       sizeof (struct open_how));
+    TEST_COMPARE (fd2, -1);
+    TEST_COMPARE (errno, ENOTDIR);
+  }
+
+  /* Remove the created file.  */
+  int cwdfd = xopen (".", O_RDONLY | O_DIRECTORY, 0);
+  TEST_COMPARE (fchdir (dir_fd), 0);
+  xunlink ("some-file");
+  TEST_COMPARE (fchdir (cwdfd), 0);
+
+  xclose (dir_fd);
+  xclose (cwdfd);
+
+  fd = openat2 (dir_fd,
+		"some-file",
+		&(struct open_how)
+		{
+		  .flags = O_CREAT|O_RDWR|O_EXCL,
+		  .mode = 0666,
+		},
+		sizeof (struct open_how));
+  TEST_COMPARE (fd, -1);
+  TEST_COMPARE (errno, EBADF);
+
+  return 0;
+}
+
+static int
+do_test (void)
+{
+  do_test_struct ();
+  do_test_flags ();
+  do_test_basic ();
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index aea7848ed6..a7f177c8a8 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2744,6 +2744,7 @@  GLIBC_2.4 sys_errlist D 0x420
 GLIBC_2.4 sys_nerr D 0x4
 GLIBC_2.4 unlinkat F
 GLIBC_2.4 unshare F
+GLIBC_2.40 openat2 F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 4ab3681914..00dfc8f1e7 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2763,3 +2763,4 @@  GLIBC_2.39 stdc_trailing_zeros_ui F
 GLIBC_2.39 stdc_trailing_zeros_ul F
 GLIBC_2.39 stdc_trailing_zeros_ull F
 GLIBC_2.39 stdc_trailing_zeros_us F
+GLIBC_2.40 openat2 F