[PATCH v7] linux: Add openat2 (BZ 31664)
Adhemerval Zanella Netto
adhemerval.zanella@linaro.org
Wed Nov 19 16:13:14 GMT 2025
On 19/11/25 09:58, Carlos O'Donell wrote:
> On 11/18/25 3:58 PM, Adhemerval Zanella wrote:
>> The openat2 syscall was added on Linux 5.6, as an extension of openat.
>> Unlike other open-like functions, the kernel only provides the LFS
>> variant (so files larger than 4GB always succeed, unlike other
>> functions with an offset larger than off_t). Also, similar to other
>> open functions, the new symbol is a cancellable entrypoint.
>>
>> The test case added only stress tests for some of the syscalls' provided
>> functionality, and it is based on an existing kernel self-test.
>>
>> A fortify wrapper is added to verify the argument size if not larger
>> than the current support open_how struct.
>>
>> Gnulib added an openat2 module, which uses read-only for the open_how
>> argument [1]. There is no clear indication whether the kernel will
>> indeed use the argument as in-out, how it would do so, or for which
>> kind of functionality [2]. Also, adding a potentially different prototype
>> than gnulib only would add extra unnecessary friction and extra
>> wrappers to handle it.
>>
>> Checked on x86_64-linux-gnu and aarch64-linux-gnu.
>
> Looking forward to a v8.
>
> Caught some more typos.
>
> Noticed that the GLIBC_2.41 for mips is fixed now, didn't catch it before
> but Claude Code LLM caught it.
>
> You can keep my RB with the typos fixed.
>
> Reviewed-by: Carlos O'Donell <carlos@redhat.com>
>> [1] https://gitweb.git.savannah.gnu.org/gitweb/?p=gnulib.git;a=commit;h=0b97ffdf32bdab909d02449043447237273df75e
>> [2] https://sourceware.org/pipermail/libc-alpha/2025-September/169740.html
>>
>> Reviewed-by: Carlos O'Donell <carlos@redhat.com>
>>
>> --
>> Changes from v6:
>> * Add manual suggestions from Paul Eggert.
>> * Removed RESOLVE_CACHED documentation.
>> * Remove EAGAIN documentation.
>> * Removed __restrict usage.
>> * Added fortify wrapper.
>>
>> ---
>> NEWS | 4 +
>> manual/llio.texi | 100 ++++
>> sysdeps/unix/sysv/linux/Makefile | 20 +
>> sysdeps/unix/sysv/linux/Versions | 1 +
>> 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 +
>> .../sysv/linux/bits/fcntl-linux-fortify.h | 49 ++
>> sysdeps/unix/sysv/linux/bits/fcntl-linux.h | 27 +
>> sysdeps/unix/sysv/linux/bits/openat2.h | 60 +++
>> 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/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-lfs.c | 1 +
>> sysdeps/unix/sysv/linux/tst-openat2.c | 482 ++++++++++++++++++
>> .../unix/sysv/linux/x86_64/64/libc.abilist | 1 +
>> .../unix/sysv/linux/x86_64/x32/libc.abilist | 1 +
>> 43 files changed, 868 insertions(+)
>> create mode 100644 sysdeps/unix/sysv/linux/bits/fcntl-linux-fortify.h
>> 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-lfs.c
>> create mode 100644 sysdeps/unix/sysv/linux/tst-openat2.c
>>
>> diff --git a/NEWS b/NEWS
>> index a2618545d59..90cd650cf87 100644
>> --- a/NEWS
>> +++ b/NEWS
>> @@ -26,6 +26,10 @@ Major new features:
>> such as changes to protection permissions, unmapping, relocation to
>> another location, or shrinking the size.
>> +* 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 it is a cancellable entrypoint.
>> +
>> Deprecated and removed features, and other changes affecting compatibility:
>> * Support for dumped heaps has been removed - malloc_set_state() now always
>> diff --git a/manual/llio.texi b/manual/llio.texi
>> index 806ff0a27d5..baae9866837 100644
>> --- a/manual/llio.texi
>> +++ b/manual/llio.texi
>> @@ -218,6 +218,106 @@ new, extended API using 64 bit file sizes and offsets transparently
>> replaces the old API.
>> @end deftypefun
>> +@deftp {Data Type} {struct open_how}
>> +@standards{Linux, fcntl.h}
>> +The @code{open_how} structure describes how to open a file using @code{openat2}.
>> +
>> +@strong{Portability note:} In the future, additional fields can be added
>> +to @code{struct open_how}, so that the size of this data type increases.
>> +Do not use it in places where this matters, such as structure fields in
>> +installed header files, where such a change could affect the application
>> +binary interface (ABI).
>> +
>> +The following generic fields are available.
>> +
>> +@table @code
>> +@item flags
>> +This field specifies the file creation and file status flags to use when
>> +opening the file.
>> +All of the @code{O_*} flags defined for @code{openat} are valid.
>> +The @code{openat2} is stricter than @code{openat} in rejecting unknown or
>> +conflicting values. For example, @code{openat2} rejects a mode that
>> +exceeds 07777, whereas @code{openat} silently ignores
>> +excess high-order bits.
>> +
>> +@item mode
>> +This field specifies the mode for the new file, similar to @code{mode}
>> +argument of @code{openat}. It should be in the range 0..07777.
>> +
>> +@item resolve
>> +This is a bitmask of flags that affect the resolution of file name components.
>> +Unlike @code{O_NOFOLLOW}, it affects all file name components, not just the
>> +last one. The following flags are available.
>> +
>> +@table @code
>> +@item RESOLVE_NO_XDEV
>> +Disallow traversal of mount points during path resolution (including all
>> +bind mounts).
>> +
>> +@item RESOLVE_NO_MAGICLINKS
>> +Disallow all @strong{magic-link} resolution during path resolution. Magic
>> +links are symbolic link-like objects that are found in @strong{procfs};
>> +for example the @code{/proc/pid/exe}.
>> +
>> +@item RESOLVE_NO_SYMLINKS
>> +Disallow resolution of symbolic links during path resolution.
>> +This option implies @code{RESOLVE_NO_MAGICLINKS}.
>> +
>> +@item RESOLVE_BENEATH
>> +This rejects absolute pathnames, pathnames containing @file{..}@:
>> +components that would be resolved relative to @var{dfd},
>> +and symbolic links that resolve to pathnames that would be rejected.
>> +The rejection occurs even if @var{dfd} is the root directory.
>> +
>> +@item RESOLVE_IN_ROOT
>> +Treat absolute pathnames as being relative to @var{dfd},
>> +treat a @file{..}@: component as being equivalent to @file{.}@:
>> +if it is resolved relative to @var{dfd},
>> +and treat symbolic link contents consistently with this.
>> +
>> +@end table
>> +@end deftp
>> +
>> +
>> +@deftypefun int openat2 (int @var{dirfd}, const char *@var{pathname}, const struct open_how *@var{how}, size_t @var{size})
>> +@standards{Linux, fcntl.h}
>> +@safety{@mtsafe{}@assafe{}@acsafe{}}
>> +This function is an extension of the @code{openat} and provides a superset of its
>> +functionality. @xref{Descriptor-Relative Access}.
>> +
>> +The @var{size} argument must equal @code{sizeof *@var{how}}. For portability
>> +to future API versions that may extend @code{struct open_how}, @code{*@var{how}}
>
> Remove double space. s/extend @code/extend @code/g
Ack.
>
>> +should be fully initialized, e.g., by a struct initializer, by @code{memset} to zero,
>
> Remove commas and double spaces. s/, e.g.,/e.g./g
>
Ack.
>> +or by having static storage duration.
>> +
>
>
> This whole section is a duplicate of above?
Right, I will remove the last one.
> ~~~> +For portability
>> +to future API versions that extend @code{struct open_how}, @code{*@var{how}}
>> +should be initialized either by a struct initializer or by @code{memset} to zero.
> ~~~
> Suggest removing.
>
>> +
>> +On failure, @code{openat2} returns @math{-1} and sets @code{errno}. It can
>> +fail for any of the reasons @code{openat} fails, plus the following reasons:
>> +
>> +@table @code
>> +@item E2BIG
>> +@var{size} is too large for any future extension, @code{*@var{how}} contains
>> +non-zero members that are future extensions not supported by this kernel
>> +
>> +@item EINVAL
>> +An unknown flag or invalid value was used on @code{*@var{how}}; or
>
> Remove double space. s/on @code/on @code/g
Ack.
>
>> +@code{@var{how}->mode} is non-zero, but @code{@var{how}->flags} does not contain
>> +@code{O_CREAT} or @code{O_TMPFILE}, or @var{size} is smaller than the ones supported
>> +by the kernel.
>> +@end table
>> +
>> +It can also return all the errors @code{openat} returns.
>> +
>> +Similar to @code{openat}, @code{openat2} is a cancellation point.
>> +
>> +Unlike other @code{open}-like functions, this function ignores
>> +@code{_FILE_OFFSET_BITS} and always operates in large file mode.
>> +@end deftypefun
>> +
>> +
>> @deftypefn {Obsolete function} int creat (const char *@var{filename}, mode_t @var{mode})
>> @standards{POSIX.1, fcntl.h}
>> @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{@acsfd{}}}
>> diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
>> index 199031da64a..7f622277c7e 100644
>> --- a/sysdeps/unix/sysv/linux/Makefile
>> +++ b/sysdeps/unix/sysv/linux/Makefile
>> @@ -135,6 +135,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 \
>> @@ -623,6 +624,7 @@ sysdep_routines += \
>> internal_statvfs \
>> open64_nocancel \
>> open_nocancel \
>> + openat2 \
>> openat64_nocancel \
>> openat_nocancel \
>> pread64_nocancel \
>> @@ -635,6 +637,7 @@ sysdep_routines += \
>> # sysdep_routines
>> sysdep_headers += \
>> + bits/fcntl-linux-fortify.h \
>> bits/fcntl-linux.h \
>> # sysdep_headers
>> @@ -643,7 +646,24 @@ tests += \
>> tst-fallocate64 \
>> tst-getcwd-smallbuff \
>> tst-o_path-locks \
>> + tst-openat2 \
>> + tst-openat2-lfs \
>> # 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)
>> +
>> +# openat2 only provides LFS support, the tests check if the interface is correctly
>> +# provided regardless of the flags.
>> +CFLAGS-tst-openat2-lfs.c += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE
>> +
>> endif
>> ifeq ($(subdir),elf)
>> diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions
>> index 8f4d71ad7fe..c7f199f13f2 100644
>> --- a/sysdeps/unix/sysv/linux/Versions
>> +++ b/sysdeps/unix/sysv/linux/Versions
>> @@ -341,6 +341,7 @@ libc {
>> }
>> GLIBC_2.43 {
>> mseal;
>> + openat2;
>> }
>> GLIBC_PRIVATE {
>> # functions used in other libraries
>> diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
>> index 2f049a4b410..0ded7d7a0a2 100644
>> --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
>> @@ -2771,4 +2771,5 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
>> index bebfad9de2c..408b3f655d6 100644
>> --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
>> @@ -3118,6 +3118,7 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> GLIBC_2.5 __readlinkat_chk F
>> GLIBC_2.5 inet6_opt_append F
>> diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
>> index d6341e98e7b..58dadbf1965 100644
>> --- a/sysdeps/unix/sysv/linux/arc/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
>> @@ -2532,4 +2532,5 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
>> index a9076eb3207..ad6f686928e 100644
>> --- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
>> @@ -2824,6 +2824,7 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> GLIBC_2.5 __readlinkat_chk F
>> GLIBC_2.5 inet6_opt_append F
>> diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
>> index d3be53ea257..a6ceb7e6943 100644
>> --- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
>> @@ -2821,6 +2821,7 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> GLIBC_2.5 __readlinkat_chk F
>> GLIBC_2.5 inet6_opt_append F
>> diff --git a/sysdeps/unix/sysv/linux/bits/fcntl-linux-fortify.h b/sysdeps/unix/sysv/linux/bits/fcntl-linux-fortify.h
>> new file mode 100644
>> index 00000000000..e6b414d7ef0
>> --- /dev/null
>> +++ b/sysdeps/unix/sysv/linux/bits/fcntl-linux-fortify.h
>> @@ -0,0 +1,49 @@
>> +/* Checking macros for fcntl functions. Linux version.
>> + Copyright (C) 2025 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 include <bits/fcntl-linux-fortify.h> directly; use <fcntl.h> instead."
>> +#endif
>> +
>> +#ifdef __USE_GNU
>> +
>> +extern int __REDIRECT (__openat2_alias, (int __dfd, const char *__filename,
>> + const struct open_how *__how,
>> + size_t __usize), openat2)
>> + __nonnull ((2, 3));
>> +
>> +#if !__fortify_use_clang
>> +__errordecl (__openat2_invalid_size,
>> + "the specified size is larger than sizeof (struct open_how)");
>> +#endif
>> +
>> +__fortify_function int
>> +openat2 (int __dfd, const char *__filename, const struct open_how *__how,
>> + size_t __usize)
>> + __fortify_clang_warning (__builtin_constant_p (__usize)
>> + && __usize > sizeof (struct open_how),
>> + "the specified size is larger than sizeof (struct open_how)")
>> +{
>> +#if !__fortify_use_clang
>> + if (__builtin_constant_p (__usize) && __usize > sizeof (struct open_how))
>> + __openat2_invalid_size ();
>> +#endif
>> + return __openat2_alias (__dfd, __filename, __how, __usize);
>> +}
>> +
>> +#endif /* use GNU */
>> diff --git a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
>> index f9b3de11f44..44ea6c4ef63 100644
>> --- a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
>> +++ b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
>> @@ -463,6 +463,33 @@ 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 openat, 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.
>
> s/unless one/unless one of/g
Ack.
>
>> +
>> + The kernel does not support legacy non-LFS interface. */
>> +extern int openat2 (int __dfd, const char * __filename,
>> + const struct open_how * __how,
>> + __SIZE_TYPE__ __usize)
>> + __nonnull ((2, 3));
>> +
>> #endif /* use GNU */
>> +#if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function
>> +# include <bits/fcntl-linux-fortify.h>
>> +#endif
>> +
>> __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 00000000000..a3fe858bc22
>> --- /dev/null
>> +++ b/sysdeps/unix/sysv/linux/bits/openat2.h
>> @@ -0,0 +1,60 @@
>> +/* openat2 definition. Linux specific.
>> + Copyright (C) 2025 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. */
>> +#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 e1107669767..643d3228222 100644
>> --- a/sysdeps/unix/sysv/linux/csky/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
>> @@ -2808,4 +2808,5 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
>> index a079e7d1a01..0ee1a4fd3f7 100644
>> --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
>> @@ -2845,6 +2845,7 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> GLIBC_2.5 __readlinkat_chk F
>> GLIBC_2.5 inet6_opt_append F
>> diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
>> index 421b3c742be..223f5971ef4 100644
>> --- a/sysdeps/unix/sysv/linux/i386/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
>> @@ -3028,6 +3028,7 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> GLIBC_2.5 __readlinkat_chk F
>> GLIBC_2.5 inet6_opt_append F
>> diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
>> index 1d7a1de570c..4d905a46cb8 100644
>> --- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
>> @@ -2292,4 +2292,5 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
>> index b512384ed01..024c465bb80 100644
>> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
>> @@ -2804,6 +2804,7 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> GLIBC_2.5 __readlinkat_chk F
>> GLIBC_2.5 inet6_opt_append F
>> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
>> index 223e4825ab2..b7b87a0b6d3 100644
>> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
>> @@ -2971,6 +2971,7 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> GLIBC_2.5 __readlinkat_chk F
>> GLIBC_2.5 inet6_opt_append F
>> diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
>> index f314f55e1fa..bb8e4d25d63 100644
>> --- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
>> @@ -2857,4 +2857,5 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
>> index 8a33db2cb2a..466b4392700 100644
>> --- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
>> @@ -2854,4 +2854,5 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
>> index 3f704bd87de..ac5062be2a9 100644
>> --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
>> @@ -2934,6 +2934,7 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> GLIBC_2.5 __readlinkat_chk F
>> GLIBC_2.5 inet6_opt_append F
>> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
>> index 633d031c727..8ac8426ae68 100644
>> --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
>> @@ -2932,6 +2932,7 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> GLIBC_2.5 __readlinkat_chk F
>> GLIBC_2.5 inet6_opt_append F
>> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
>> index 8b8e5af806a..5f7ab3f95d2 100644
>> --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
>> @@ -2940,6 +2940,7 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> GLIBC_2.5 __readlinkat_chk F
>> GLIBC_2.5 inet6_opt_append F
>> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
>> index f45d5075fdf..b6543a8773f 100644
>> --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
>> @@ -2842,6 +2842,7 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> GLIBC_2.5 __readlinkat_chk F
>> GLIBC_2.5 inet6_opt_append F
>> diff --git a/sysdeps/unix/sysv/linux/openat2.c b/sysdeps/unix/sysv/linux/openat2.c
>> new file mode 100644
>> index 00000000000..d45eb05c327
>> --- /dev/null
>> +++ b/sysdeps/unix/sysv/linux/openat2.c
>> @@ -0,0 +1,29 @@
>> +/* Linux openat2 syscall implementation.
>> + Copyright (C) 2025 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,
>> + const 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 96b056d14a0..160dff8c79f 100644
>> --- a/sysdeps/unix/sysv/linux/or1k/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist
>> @@ -2282,4 +2282,5 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
>> index 6420f23d068..16653ba77f3 100644
>> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
>> @@ -3161,6 +3161,7 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> GLIBC_2.5 __readlinkat_chk F
>> GLIBC_2.5 inet6_opt_append F
>> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
>> index 9a2a258e024..a453e237446 100644
>> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
>> @@ -3206,6 +3206,7 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> GLIBC_2.5 __readlinkat_chk F
>> GLIBC_2.5 inet6_opt_append F
>> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
>> index 6a20d8d031a..7d01a4f1cbf 100644
>> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
>> @@ -2915,6 +2915,7 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> GLIBC_2.5 __readlinkat_chk F
>> GLIBC_2.5 inet6_opt_append F
>> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
>> index c0fa82e6a2a..f5c1927d347 100644
>> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
>> @@ -2991,4 +2991,5 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
>> index 5c46dcacdce..366c7405325 100644
>> --- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
>> @@ -2535,4 +2535,5 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
>> index 4ce2007c56d..7c80ed4bc4a 100644
>> --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
>> @@ -2735,4 +2735,5 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
>> index 9a672c6a4c3..0aa665c18e9 100644
>> --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
>> @@ -3159,6 +3159,7 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> GLIBC_2.5 __readlinkat_chk F
>> GLIBC_2.5 inet6_opt_append F
>> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
>> index 1926e675ca9..f2bf32ed957 100644
>> --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
>> @@ -2952,6 +2952,7 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> GLIBC_2.5 __readlinkat_chk F
>> GLIBC_2.5 inet6_opt_append F
>> diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
>> index b3510af9ef7..2b6d77d8ff3 100644
>> --- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
>> @@ -2851,6 +2851,7 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> GLIBC_2.5 __readlinkat_chk F
>> GLIBC_2.5 inet6_opt_append F
>> diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
>> index fc1fea412a5..65b990f5ea9 100644
>> --- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
>> @@ -2848,6 +2848,7 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> GLIBC_2.5 __readlinkat_chk F
>> GLIBC_2.5 inet6_opt_append F
>> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
>> index fce9f948b79..2fc6479c2c2 100644
>> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
>> @@ -3182,6 +3182,7 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> GLIBC_2.5 __readlinkat_chk F
>> GLIBC_2.5 inet6_opt_append F
>> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
>> index 9d4721c16eb..2446991f288 100644
>> --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
>> @@ -2818,6 +2818,7 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> GLIBC_2.5 __readlinkat_chk F
>> GLIBC_2.5 inet6_opt_append 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 00000000000..9b65d184d73
>> --- /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) 2025 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-lfs.c b/sysdeps/unix/sysv/linux/tst-openat2-lfs.c
>> new file mode 100644
>> index 00000000000..85962d30c17
>> --- /dev/null
>> +++ b/sysdeps/unix/sysv/linux/tst-openat2-lfs.c
>> @@ -0,0 +1 @@
>> +#include "tst-openat2.c"
>> diff --git a/sysdeps/unix/sysv/linux/tst-openat2.c b/sysdeps/unix/sysv/linux/tst-openat2.c
>> new file mode 100644
>> index 00000000000..e52e3870d04
>> --- /dev/null
>> +++ b/sysdeps/unix/sysv/linux/tst-openat2.c
>> @@ -0,0 +1,482 @@
>> +/* Linux openat2 tests.
>> + Copyright (C) 2025 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 <array_length.h>
>> +#include <errno.h>
>> +#include <fcntl.h>
>> +#include <libgen.h>
>> +#include <stdint.h>
>> +
>> +#include <support/check.h>
>> +#include <support/support.h>
>> +#include <support/temp_file.h>
>> +#include <support/test-driver.h>
>> +#include <support/xunistd.h>
>> +
>> +static int dir_fd;
>> +static char *temp_dir;
>> +static char *temp_subdir;
>> +static char *temp_some_file;
>> +
>> +#define TEST_DIR_LINK "test_dir_link"
>> +#define TEST_DIR_LINK_2 "test_dir_link_2"
>> +#define TEMP_DIR_LINK "temp_dir_link"
>> +#define INVALID_LINK "invalid-link"
>> +#define VALID_LINK "valid-link"
>> +
>> +static void
>> +create_symlink (const char *target, const char *linkpath)
>> +{
>> + TEST_VERIFY_EXIT (symlinkat (target, dir_fd, linkpath) == 0);
>> + add_temp_file (xasprintf ("%s/%s", temp_dir, linkpath));
>> +}
>> +
>> +static void
>> +do_prepare (int argc, char *argv[])
>> +{
>> + /*
>> + Construct a test directory with the following structure:
>> +
>> + temp_dir/
>> + |- tst-openat2.xxxxxxx
>> + |- test_dir_link -> test_dir (/tmp)
>> + |- test_dir_link_2 -> test_dir_link
>> + |- temp_dir_link -> temp_dir/tst-openat2.xxxxxxx
>> + |- some-file.xxxxxxx
>> + |- invalid_link -> temp_dir/tst-openat2.xxxxxxx/some-file.xxxxxxx
>> + |- valid_link -> some-file.xxxxxxx
>> + |- subdir.xxxxxxx
>> + |- some-file.xxxxxxx
>> + */
>> +
>> + temp_dir = support_create_temp_directory ("tst-openat2.");
>> + dir_fd = xopen (temp_dir, O_RDONLY | O_DIRECTORY, 0);
>> +
>> + create_symlink (test_dir, TEST_DIR_LINK);
>> + create_symlink (TEST_DIR_LINK, TEST_DIR_LINK_2);
>> + create_symlink (temp_dir, TEMP_DIR_LINK);
>> +
>> + {
>> + char *filename;
>> + int fd = create_temp_file_in_dir ("some-file.", temp_dir, &filename);
>> + TEST_VERIFY_EXIT (fd != -1);
>> +
>> + create_symlink (filename, INVALID_LINK);
>> +
>> + create_symlink (basename (filename), VALID_LINK);
>> + }
>> +
>> + temp_subdir = support_create_temp_directory (xasprintf ("%s/subdir.",
>> + basename (temp_dir)));
>> + {
>> + int fd = create_temp_file_in_dir ("some-file.", temp_subdir,
>> + &temp_some_file);
>> + TEST_VERIFY_EXIT (fd != -1);
>> + }
>> +}
>> +#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 (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
>> + {
>> + const char *path;
>> + 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++)
>> + {
>> + const char *path;
>> + if (t->how.flags & O_CREAT)
>> + {
>> + char *newfile;
>> + int temp_fd = create_temp_file ("tst-openat2.", &newfile);
>> + TEST_VERIFY_EXIT (temp_fd != -1);
>> + xunlink (newfile);
>> + path = newfile;
>> + }
>> + else
>> + path = ".";
>> +
>> + 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 void
>> +do_test_resolve (void)
>> +{
>> + int fd;
>> +
>> + /* TEMP_DIR_LINK links to the absolute temp_dir, which escapes the temporary
>> + test directory. */
>> + fd = openat2 (dir_fd,
>> + TEST_DIR_LINK,
>> + &(struct open_how)
>> + {
>> + .resolve = RESOLVE_BENEATH,
>> + },
>> + sizeof (struct open_how));
>> + TEST_COMPARE (fd, -1);
>> + TEST_COMPARE (errno, EXDEV);
>> +
>> + /* Same as before, TEMP_DIR_LINK_2 links to TEMP_DIR_LINK. */
>> + fd = openat2 (dir_fd,
>> + TEST_DIR_LINK_2,
>> + &(struct open_how)
>> + {
>> + .resolve = RESOLVE_BENEATH,
>> + },
>> + sizeof (struct open_how));
>> + TEST_COMPARE (fd, -1);
>> + TEST_COMPARE (errno, EXDEV);
>> +
>> + /* TEMP_DIR_LINK links to the temproary directory itself (dir_fd). */
>
> Fix spelling. s/temproary/temporary/g
Ack.
>
>> + fd = openat2 (dir_fd,
>> + TEMP_DIR_LINK,
>> + &(struct open_how)
>> + {
>> + .resolve = RESOLVE_BENEATH,
>> + },
>> + sizeof (struct open_how));
>> + TEST_COMPARE (fd, -1);
>> + TEST_COMPARE (errno, EXDEV);
>> +
>> + /* Although it points to a valid file in same path, the link refers to
>> + an absolute path. */
>> + fd = openat2 (dir_fd,
>> + INVALID_LINK,
>> + &(struct open_how)
>> + {
>> + .resolve = RESOLVE_BENEATH,
>> + },
>> + sizeof (struct open_how));
>> + TEST_COMPARE (fd, -1);
>> + TEST_COMPARE (errno, EXDEV);
>> +
>> + fd = openat2 (dir_fd,
>> + VALID_LINK,
>> + &(struct open_how)
>> + {
>> + .resolve = RESOLVE_BENEATH,
>> + },
>> + sizeof (struct open_how));
>> + TEST_VERIFY (fd != -1);
>> + xclose (fd);
>> +
>> + /* There is no such file in temp_dir/tst-openat2.xxxxxxx. */
>> + fd = openat2 (dir_fd,
>> + "should-not-work",
>> + &(struct open_how)
>> + {
>> + .resolve = RESOLVE_IN_ROOT,
>> + },
>> + sizeof (struct open_how));
>> + TEST_COMPARE (fd, -1);
>> + TEST_COMPARE (errno, ENOENT);
>> +
>> + {
>> + int subdir_fd = openat2 (dir_fd,
>> + basename (temp_subdir),
>> + &(struct open_how)
>> + {
>> + .flags = O_RDONLY | O_DIRECTORY,
>> + .resolve = RESOLVE_IN_ROOT,
>> + },
>> + sizeof (struct open_how));
>> + TEST_VERIFY (subdir_fd != -1);
>> +
>> + /* Open the file within the subdir.xxxxxx with both tst-openat2.xxxxxxx
>> + and tst-openat2.xxxxxxx/subdir.xxxxxxx file descriptors. */
>> + fd = openat2 (subdir_fd,
>> + basename (temp_some_file),
>> + &(struct open_how)
>> + {
>> + .resolve = RESOLVE_IN_ROOT,
>> + },
>> + sizeof (struct open_how));
>> + TEST_VERIFY (fd != -1);
>> + xclose (fd);
>> +
>> + fd = openat2 (dir_fd,
>> + xasprintf ("%s/%s",
>> + basename (temp_subdir),
>> + basename (temp_some_file)),
>> + &(struct open_how)
>> + {
>> + .resolve = RESOLVE_IN_ROOT,
>> + },
>> + sizeof (struct open_how));
>> + TEST_VERIFY (fd != -1);
>> + xclose (fd);
>> + }
>> +}
>> +
>> +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)
>> +{
>> + if (openat2 (AT_FDCWD, ".", &(struct open_how) {}, sizeof (struct open_how))
>> + == -1 && errno == ENOSYS)
>> + FAIL_UNSUPPORTED ("openat2 is not supported by the kernel");
>> +
>> + do_test_struct ();
>> + do_test_flags ();
>> + do_test_resolve ();
>> + 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 a836a574266..941a4835104 100644
>> --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
>> @@ -2767,6 +2767,7 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>> GLIBC_2.5 __readlinkat_chk F
>> GLIBC_2.5 inet6_opt_append F
>> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
>> index aecce5bbc5e..a5714cf59f5 100644
>> --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
>> @@ -2786,4 +2786,5 @@ GLIBC_2.43 __memset_explicit_chk F
>> GLIBC_2.43 memalignment F
>> GLIBC_2.43 memset_explicit F
>> GLIBC_2.43 mseal F
>> +GLIBC_2.43 openat2 F
>> GLIBC_2.43 umaxabs F
>
>
More information about the Libc-alpha
mailing list